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.
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 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.
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.
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.
Speaking of events we know that the touch screen method onTouchEvent (MotionEvent events) allows you to capture touch events on the screen and event.getX () and
event.getY () give me the coordinates of the touch as float values (ie values with a comma).
Specifically, I realized that taking logcat using the fixed point the finger in a mobile phone screen and not moving it, the event is not only perceived but MotionEvent.ACTION_DOWN MotionEvent.ACTION_MOVE and returned coordinates are manifold. This i can understand because the surface of the finger touches more points and more by reading the device coordinates believe that the finger moves while holding it.
My problem is that I would read the color of one pixel of a color image when I hold your finger still. In particular I need the central area occupied by the finger.
First, assuming you have a Bitmap object, I have to round to integer coordinates of the touch as the getPixel (intX, int y) coordinates of the entire Bitmap wants to return the pixel color.
Then how do I get the central point of touch? Be that there is a function that can help me? Keep in mind that while I stopped and read the value of a pixel on the image then I start to move slowly and even though I always record every move the center pixel. I need this because every move, if you change the color of the image in pixels, I want to vibrate or not the device.
If I could stop thinking about themselves in a dynamic array to store the coordinates of different pixels and search for the center of gravity, but moving I do not know what to do. I think however, that the research center of gravity, if not done very efficiently, can be slow during the move and then give the wrong results. If the CG is not quite enough for me to another point belonging to the environment.
I hope you can help me maybe with a few lines of code sketched.
Thanks in advance.
To get the touch position of finger, just cast the getX() and getY() to int and perform your desired tasks.
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN ) {
getPixelAt((int)event.getX(), (int)event.getY());
}
}
you can put you on main activity class when you can want to touch event occurs. let see you can put following code or not ? and return is most important as well.
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mDistanceX = 0;
}
return super.onTouchEvent(event);
}