So what I'm trying to make is a little space game, You control the ship with a graphic on-screen joystick using touch and drag. I have gotten this to work fine. The problem arises once I started to try and add the ability to touch the top portion of the screen to fire a weapon. For some reason, if you are currently dragging the joystick it seems to ignore the other touch input and doesn't do anything (But it works fine once I stop holding the joystick).
This is my both my first time working with java, and with Android so its probably something stupid, but iv been stuck on it for a few days.
Anyway, here my code.
The below is from my
public class Panel extends SurfaceView implements SurfaceHolder.Callback {
#Override
public boolean onTouchEvent(MotionEvent event) {
fingers= event.getPointerCount(); //Returns 1 or 2 properly if 2 fingers on screen
playership.onTouchEvent(event); //Pass the event along to the spaceship object
return true;
//return super.onTouchEvent(event); //no idea what this does, but it seems to disable the drag event
}
Below is the playership.onTouchEvent(event); function
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
if(event.getY()<(Panel.mHeight-150))
{
Laser1.reset(mX,mY,(int)event.getX(),(int)event.getY());
}
break;
}
joy1.onTouchEvent(event);
return true;
}
And below is the joy1.onTouchEvent(event);
public boolean onTouchEvent(MotionEvent event) {
int eventaction = event.getAction();
//Offset between mouse(x,y) and center
double offx=oX-event.getX();
double offy=oY-event.getY();
double d=Math.sqrt((offx*offx)+(offy*offy));
switch (eventaction )
{
case MotionEvent.ACTION_DOWN:
if(d<dragrange) //Start Dragging if clicked
{
offx=offx/d;
offy=offy/d;
Dragging=true;
reset = false;
dX=(int) (offx*dragrange);
dY=(int) (offy*dragrange);
}
break;
case MotionEvent.ACTION_MOVE:
if(Dragging)//if joy is already being draged, update it.
{
offx=offx/d;
offy=offy/d;
if(d>dragrange)
{
dX=(int) (offx*dragrange);
dY=(int) (offy*dragrange);
}
else
{
dX=(int) (offx*d);
dY=(int) (offy*d);
}
reset = false;
}
break;
case MotionEvent.ACTION_UP:
if(Dragging)
{
Dragging=false;
}
break;
}
return true;
}
So yeah, the problem is that if the joystick is in the middle of a case MotionEvent.ACTION_MOVE it seems to block any other touch events from properly registering.
You need to handle detecting the other finger. More specifically handling
MotionEvent.ACTION_POINTER_DOWN and MotionEvent.ACTION_POINTER_UP
otherwise you're ignoring other fingers. Here is some code from one of my projects that does exactly what you're looking for:
public void onTouchEvent(MotionEvent event)
{
int ptrId = -1;
int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
down(event.getPointerId(0), (int)event.getX(), (int)event.getY());
break;
case MotionEvent.ACTION_UP:
up(event.getPointerId(0));
break;
case MotionEvent.ACTION_POINTER_DOWN:
ptrId = action >> MotionEvent.ACTION_POINTER_ID_SHIFT;
int ptrIdx = event.findPointerIndex(ptrId);
down(ptrId, (int)event.getX(ptrIdx), (int)event.getY(ptrIdx));
break;
case MotionEvent.ACTION_POINTER_UP:
ptrId = action >> MotionEvent.ACTION_POINTER_ID_SHIFT;
up(ptrId);
break;
case MotionEvent.ACTION_MOVE:
for(int i = 0; i < event.getPointerCount(); ++i)
if(event.getPointerId(i) == inputPad.id())
{
inputPad.position(event.getX(inputPad.id()));
player.velocity(inputPad.delta());
player.stand();
if(enemy != null) {
Fighter.collide(player, enemy);
enemy.update();
}
player.update();
break;
}
break;
}
}
See here and here for more explanation.
Related
I am making a single screen application of a simple logic circuit. I am using onTouchEvent to handle user interactions. I am using ACTION_UP, ACTION_MOVE, & ACTION_DOWN right now, but this only allows me to use one gesture. I want to be able to selection an option in my UI, such as "AND" gate. I want to use one touch to select what I want to do, then the next touch to place the gate on the screen. Instead, my onTouchEvent only allows me to touch the component I want and I have to keep my finger on the screen to drag it to the location I want to place it. This is not want I want.
I've tried researching how to implement some sort of state variable to allow onTouchEvent to wait for the next touch, but I don't think I correctly understand how to implement it.
#Override
public boolean onTouchEvent(MotionEvent motionEvent) {
Log.d("Debugging", "In onTouchEvent");
if((motionEvent.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
Touch.horizontalTouched = (int)motionEvent.getX()/ grid.getBlockSize();
Touch.verticalTouched = (int)motionEvent.getY()/ grid.getBlockSize();
whatWasTouched = whatWasTouched(Touch.horizontalTouched, Touch.verticalTouched);
}else if((motionEvent.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_MOVE){
//do nothing, finger is moving on screen
}
else if((motionEvent.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP){
Touch.secondHorizontalTouch = (int)motionEvent.getX()/ grid.getBlockSize();
Touch.secondVerticalTouch = (int)motionEvent.getY()/ grid.getBlockSize();
placeComponent();
draw();
}
return true;
}
I expect my first touch on the screen to be able to select an option, ex: "AND", "OR", "NOT", "SWITCH", "EDIT", etc. and then my second touch completes the desired action. I also want to be able to touch a component I placed on the screen and then touch another component so I can wire them together.
By default, event listeners in Android are for waiting - you don't have to provide any delay.
Simply set the onTouchEvent(...) listener on the ImageView and show the first bitmap. When the ImageView is touched, show the next bitmap and so on. All you have to do is keep a count of how many touches there have been in order to know which image to show (image 1, 2, 3, 4 etc).
Example...
public class LoadImage extends Activity {
int imageNumber = 1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_load_image);
//get an image and create a bitmap from it
ImageView imageView = (ImageView) findViewById(R.id.imageView);
imageView.setImageBitmap(bitmap);
}
#Override
public boolean onTouchEvent(MotionEvent evt) {
if (evt.getAction() == MotionEvent.ACTION_DOWN) {
imageNumber++;
switch (imageNumber) {
case 2:
// show image 2
break;
case 3:
// show image 3
break;
...
}
return true;
}
return false;
}
}
I was able to figure this out by using a static class that will handle the state of my touches.
#Override
public boolean onTouchEvent(MotionEvent motionEvent) {
Log.d("Debugging", "In onTouchEvent");
if (placeState.getState() == false) {
if ((motionEvent.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) {
Touch.horizontalTouched = (int) motionEvent.getX() / grid.getBlockSize();
Touch.verticalTouched = (int) motionEvent.getY() / grid.getBlockSize();
whatWasTouched = whatWasTouched(Touch.horizontalTouched, Touch.verticalTouched);
if(whatWasTouched.equals("DELETE")){
visualComponents.clear();
logicalComponents.clear();
}
placeState.toggleState();//sets to true
draw();
}
}else if (placeState.getState() == true) {
Touch.secondHorizontalTouch = (int) motionEvent.getX() / grid.getBlockSize();
Touch.secondVerticalTouch = (int) motionEvent.getY() / grid.getBlockSize();
placeComponent();
placeState.toggleState();//sets to false
draw();
}
return true;
}
I thought this is a pretty relevant and common question, but I couldnt find an answer.
At the moment I have this method:
public boolean onTouchEvent (MotionEvent evt){
if (evt.getAction() == MotionEvent.ACTION_DOWN) {
do stuff ...
}
}
So if the user taps on the screen (wherever) the code is executed. Now I want the distinction between the right side of the display and the left side (left side means --> go back).
You can do this many ways. Here is one of them:
Attach onTouch listener to the view, which stretches to its edges. (For example your RelativeLayout which holds rest of views)
private View.OnTouchListener onTouchListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
float halfOfAScreen = mainLayout.getMaxWidth() / 2;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
float fingerPosition = event.getX();
if(fingerPosition < halfOfAScreen) {
onBackPressed();
}
return true;
default:
return false;
}
}
};
Refer to this post on how to get touch position.
It seems in your case you will use
int x = (int)event.getX();
int y = (int)event.getY();
and work within the bounds of your layout that you want the app to react to.
I tried to explain my issue through image, what i am looking for.
I tried
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
switch (action) {
case (MotionEvent.ACTION_DOWN):
// Log.d(DEBUG_TAG,"Action was DOWN");
return true;
case (MotionEvent.ACTION_MOVE):
// Log.d(DEBUG_TAG,"Action was MOVE");
return true;
case (MotionEvent.ACTION_UP):
// Log.d(DEBUG_TAG,"Action was UP");
return true;
case (MotionEvent.ACTION_CANCEL):
// Log.d(DEBUG_TAG,"Action was CANCEL");
return true;
case (MotionEvent.ACTION_OUTSIDE):
// Log.d(DEBUG_TAG,"Movement occurred outside bounds " +
// "of current screen element");
return true;
default:
return super.onTouchEvent(event);
}
I worked on ACTION_DOWN & ACTION_MOVE but didn't find what I am looking for
I have a listview and I set an onClickListener and an onTouchListener. The click listener for when they click on an item, I had just this and everything thing worked fine. But, when I added the touch listener to watch for left and right swipes, it won't let me scroll anymore.
listview.setOnTouchListener(new OnTouchListener(){
public boolean onTouch(View v, MotionEvent event){
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
historicX = event.getX();
historicY = event.getY();
break;
case MotionEvent.ACTION_UP:
if(event.getX() - historicX < -DELTA){
slidingLeft(event.getX(),event.getY());
return true;
}
else if(event.getX() - historicX > DELTA){
slidingRight(event.getX(), event.getY());
return true;
}
break;
default: return true;
}
return false;
}
});
How can I have to able to scroll through the listview again. Is there another listener I could add to do this, or could I modify the onTouchListener to watch for scrolls too?
You should use GestureDetector .
You can use example from here, it is very clear.
https://stackoverflow.com/a/12938787/1374065
I have created multiple views dynamically , in my case textViews. i have given them ids. what iwant is to select all the textViews ids over which i slide my finger. E.g if there are textviews saying A And B and when i slide finger from A to b i should get ids save in my array. Currently I am learning touch. I don't know how to implement it.
Best Regards
OnTouchListener MyOnTouchListener = new OnTouchListener(){
public boolean onTouch(View v, MotionEvent event)
{
Drawable d = getResources().getDrawable(R.drawable.small_corners);
switch(event.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
vibe.vibrate(20);
id.add(v.getId());
TextView vv = (TextView) v;
val.add(vv.getText().toString());
vv.setBackgroundDrawable(d);
String str = "";
//A pressed gesture has started, the motion contains the initial starting location.
return false;
case MotionEvent.ACTION_POINTER_DOWN:
//A non-primary pointer has gone down.
break;
case MotionEvent.ACTION_MOVE:
//A change has happened during a press gesture (between ACTION_DOWN and ACTION_UP).
int check = 0;
for (int i = 0; i < id.size(); i ++)
{
if (id.get(i) == v.getId())
check = 1;
}
if (check != 1)
{
id.add(v.getId());
vv = (TextView) v;
val.add(vv.getText().toString());
vv.setBackgroundDrawable(d);
}
return false;
case MotionEvent.ACTION_MASK:
//A change has happened during a press gesture (between ACTION_DOWN and ACTION_UP).
break;
case MotionEvent.ACTION_OUTSIDE:
//A change has happened during a press gesture (between ACTION_DOWN and ACTION_UP).
break;
case MotionEvent.ACTION_UP:
//A pressed gesture has finished.
break;
case MotionEvent.ACTION_POINTER_UP:
//A non-primary pointer has gone up.
break;
}
return false;
}
};
Did you tried ACTION_HOVER_ENTER and ACTION_HOVER_EXIT?
It might do the trick. See example in documentation of onGenericMotionEvent.
From what I have understood, try this; Implement onTouchlistner and set this listener for all of your TextViews, in onTouch() do this:
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction() == MotionEvent.ACTION_MOVE){
//SAVE YOUR VIEWS ID//
someArray[index] = ((TextView)v).getId())
return true;
}
return false;
}
Try different ACTIONS of MotionEvent