In my game app that uses AndEngine, I'm trying to detect a swipe motion over a button Sprite to enlarge the button when the finger is over the button Sprite, and set scale back to 1.0f when the finger swipes off the Sprite. Meaning:
finger down outside button area
swipe over button (and button is sized up) but keep finger down
continue swipe off button and button goes back to orginal scale.
I've tried following:
myButton = new Sprite(posX, posY, resourcesManager.rightButtonRegion, vbom) {
#Override
public boolean onAreaTouched(final TouchEvent pAreaTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
switch (pAreaTouchEvent.getAction()) {
case TouchEvent.ACTION_DOWN:
this.setScale(1.25f);
break;
case TouchEvent.ACTION_UP:
this.setScale(1.0f);
break;
case TouchEvent.ACTION_MOVE:
this.setScale(1.0f);
break;
case TouchEvent.ACTION_OUTSIDE:
this.setScale(1.0f);
break;
}
return true;
}
};
But if I start the swipe outside of the button and move my finger over the button the button is not scaled up in size. Appreciate any pointers to how to achieve this effect. If there is an non-Andengine solution using SurfaceView I'd appreciate any perspective on that too.
You only set scale on TouchEvent.ACTION_DOWN. When you slide into your touch region, it does not register an ACTION_DOWN because you didn't press down in your region, you just moved into it. Perhaps you could put a check into your case TouchEvent.ACTION_MOVE: that scales up the first time you move into that region, if your touch sequence did not being with ACTION_DOWN.
If that doesn't work, you can use things like onGenericMotionEvent(MotionEvent) that deliver other types of motion event information.
Related
I have this ImageView:
I need to be able to rotate the whole image (The circle and the two "30" circles)
when I drag the outside circles around. It should rotate only if I start dragging from the outside "30" circles
They should all rotate around the dot in the center.
I managed to make this image rotate when I drag it in any part of it using a View.OnTouchListener and by calculating the angle between the touch event coordinates and the pivot point, and then rotate the imageView.
How can I detect when the motion event is in the outer circles only, to prevent the image from rotating when dragging inside the big circle?
In OnTouchListener's onTouchEvent method, you can utilize the ACTION_DOWN event to check, if a TouchEvent starts inside the little outer circles. If this is true, set a boolean to true. In the ACTION_MOVE event, you just have to check the boolean and only rotate if it is set to true. Then, use ACTION_UP and ACTION_CANCEL to set the boolean to false again.
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
boolean rightPosition = false;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// When the event is in the little circles rightPosition=true
break;
case MotionEvent.ACTION_MOVE:
if(rightPosition) yourRotationCode();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
rightPosition = false;
}
return false;
}
How do you know, if the drag starts in the little circles?
Tl;dr: Keep track of the polar coordinates of the little circles and compare them with the ACTION_DOWN event's coordinates.
To determine, if the ACTION_DOWN event occurs inside the little circles, keep track of the angle, your ImageView is rotated from it's 'zero position'. In the beginning, the little circles are at 45° and 125°. Offset them against the current rotation of your ImageView, get the angle between 12 o'clock and the ACTION_DOWN event and compare them. Also take into account the distance between the point of rotation and the event. As you already calculate the needed rotation, I think you know how to determine these angles.
The right distance from the point of rotation should be calculated from the ImageView's height and width, so you remain density independent. This needs some pixel counting and calculating the ratio, based on the original image resource, done by hand. This ratio can then be hard coded to a constant value.
As the position of an TouchEvent is precise to one pixel, you should add some offset around the calculated center of the little circles. I would recommend a square around the little circle. Its side length has again to be calculated in aspect to the ImageView's height and width. Again you can determine the ratio of your 'valid area' to the size of the ImageView by hand and provide it as a constant. Then you just have to check if the starting point's coordinates are within +/-(side length / 2) of the center of the little circles.
I am a beginner developer. I would like to build an app, but I am facing a problem.
As the image shows, I have a button. If the user clicks on the top side of this button I would like to change the color of just the top line. Also on the other sides, just the side that the user clicked. If user clicked for example on the top side then the right side, I would like to change the color of both side which is shown by the picture.
Any ideas how to do this? The main problem for me, is I can not detect which area the user clicks.
You can use touch detection like described here:
https://developer.android.com/training/gestures/detector.html
#Override
public boolean onSingleTapConfirmed(MotionEvent event) {
float clickedX = event.getX();
float clickedY = event.getY();
float btnTop = obtainTop(yourBtn);
float btnBot = obtainBot(yourBtn);
float btnLeft = obtainLeft(yourBtn);
float btnRight = obtainRight(yourBtn);
// detect where the button was clicked
// change button how you need
return true;
}
For obtain x y coordinates of View you can find something here
Getting View's coordinates relative to the root layout
I'm trying to draw a resizable Circle in android with user Touch events.
I need that when user touch the scree, the circle will be drawn, then if he moves the finger outter of its center the circle will be go bigger and vice versa, how can i do that??
Also, he is like redrawing the circle, that's because in the ACTION_MOVE there is this sentence that says:
canvas.drawCircle(...)
But how can i work with the starting circle and make it bigger or smaller??
I have already tried a lot of things(for like 6 hours) and I don't know what else to try, this is my current code:
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
cacheCanvas.drawCircle(event.getX(),event.getY(),50,paint);
pX= event.getX();
pY = event.getY();
circleDiam = (event.getX()+event.getY())/2;
break;
case MotionEvent.ACTION_MOVE:
cacheCanvas.drawCircle(event.getX(),event.getY(),(event.getX()+event.getY())/2,paint);
break;
case MotionEvent.ACTION_UP:
break;
}
invalidate();
return true;
}
This is the result i got:
http://i.stack.imgur.com/J0y7s.png
Very thanks in advance!
You want to use a SurfaceView to draw the circle and then
listen to the touch events on the surface view.
http://developer.android.com/reference/android/view/SurfaceView.html
There are some very good examples of using surface views available online
if you google for them.
If you only have a couple of sizes and you want to go cheesy on it you could define drawables and swap them in as the user drags. This would not be graceful or smooth.
I saw a similar question posted here: Detect touch event on a view when dragged over from other view. But that question has different behaviour compared to what I want.
If I have multiple views, I press on one and continue dragging my finger onto multiple other views, is there a way for the other views to be notified that they have been touched? It won't be just 2 views, it could be multiple views. I click on one and keep dragging my finger and go over multiple other views.
The views are dynamically made and programmatically added to a FrameLayout and positioned programmatically by adding margins around it.
I couldn't find a way to do this through the actual custom views and had to go one layer back.
The position of the views are documented on the FrameLayout that contains each view.
In the FrameLayout, I ended up overwriting onTouchEvent.
I ended up having to do something similar to this:
#Override
public boolean onTouchEvent(MotionEvent event) {
float xCoord = event.getX();
float yCoord = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Using X and Y coordinates, find out if touch event is on top of a view.
// Mark the view as touched
return true;
case MotionEvent.ACTION_UP:
// Action required once touch released.
return true;
default:
// When dragging, the default case will be called.
// Using X and Y coordinates, figure out if finger goes over a view.
// If you don't want same behaviour when going back to previous view,
// then mark it so you can ignore it if user goes back to previous view.
}
}
Once case MotionEvent.ACTION_UP gets called, you can use the fact that the views were marked to know which ones were touched. You can also get the order if required by putting the views in an array when marking them.
My application is a grid of buttons, edge to edge. I'm overriding all touch and motion events and controlling the behavior manually. Everything is working fine, except for when a finger is dragged off-screen. MotionEvent.ACTION_UP is triggered, and I don't want that. I tried using getRawX() and getRawY() to determine if (for example, for the top and left edges) the coordinate is < 1, but the value will be higher (as high as 20) if a finger is dragged quickly. When ACTION_UP is triggered, the location values seem to lag behind a bit. Is there a way around this? ACTION_CANCEL doesn't seem to get triggered at all.
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case (MotionEvent.ACTION_DOWN):
Log.i(classID, "action down");
return true;
case (MotionEvent.ACTION_CANCEL):
Log.i(classID, "action cancel");
// never called
return true;
case (MotionEvent.ACTION_MOVE):
Log.i(classID, "action move");
return true;
case (MotionEvent.ACTION_UP):
Log.i(classID, "action up");
Log.i(classID, "position: " + (int)event.getRawX() + "/" + (int)event.getRawY());
return true;
}
return false;
}
There is physical or logical no difference between the two (finger falling off the screen and lifting your finger). When your finger goes off the screen, you have "lifted ", or, better worded, removed your finger from the screen. MotionEvent.ACTION_UP is a place holder for any motion event that results in no touch input data being provided to the system.
If you wish to work around this, you could possibly create a parent view and child view. If the touch is "lifted" from the child view but still in the parent, the finger is still on the device but out of bounds.
What he said about there being 'no physical difference' between the finger being lifted off the screen and the finger being swiped out of the borders of your View is incorrect.
You can prove so by merely having a SurfaceView in the middle of your screen, and in the OnTouch event callback, have an IF statement such as:
if (event.getEvent() == MotionEvent.ACTION_UP) {
Log.d("derp", "finger has lifted up");
}
You'll see that it doesn't actually report if your finger merely goes out of the boundaries. Although there is a MotionEvent.ACTION_OUTSIDE, I can't seem to get it working. Hence why I'm looking about here too.