I am overriding onInterceptTouch(MotionEvent) for the purpose of allowing horizontal scrolling. What I am finding however is that I cannot detect when the user has touched the embedded v. The x,y on the view are like 2000, 2400 while the MotionEvent.getX(),getY() are like 400,500
View v = findViewById(R.id.myView);
Rect r = new Rect();
v.getHitRect(r);
int[] loc = new int[2];
v.gtLocationOnScreen(loc);
int x = loc[0];
int y = loc[1];
// Result x,y are huge numbers 2400, etc
// event.getX() is 30, event.getY() == 500 nothing close to 2400.
if (r.contains((int)event.getX(), (int)event.getY())
{
return false; // this is never true even when I click right on View v.
}
I know this is an old question and is mostly answered in the linked post, but I just came across this problem so I thought I'd fill in my solution.
private boolean isTouchInView(View view, MotionEvent event) {
Rect hitBox = new Rect();
view.getGlobalVisibleRect(hitBox);
return hitBox.contains((int) event.getRawX(), (int) event.getRawY());
}
Try using getRawX() and getRawY(). These will give you the absolute positions you need.
See:
How do I know if a MotionEvent is relative or absolute?
You also have to adjust the location of your destination view to account for any displacement by other views like so:
int[] screenLocation = new int[2];
view.getLocationOnScreen(screenLocation);
hitRect.offset(screenLocation[0] - view.getLeft(), screenLocation[1] - view.getTop());
//Then check if source view is contained in target view
x=event.getRawX();
y=event.getRawY();
if (hitRect.contains(x, y)) {
//do your stuff
}
Related
I have used the following methods but no success
Integer [] location = new Integer[];
view.getLocationOnScreen(location);
getLocationInWindow(int[]) MyCode: int[] locatoins = new int[2];
rulerLyt.findViewById(2).getLocationInWindow(locatoins);
x = locatoins[0];
float y = 0f;
y = locatoins[1];
imgBaby.setTranslationX(x);
imgBaby.setTranslationY(y);
Please give your comment/solution to achieve this
These are easily accessible methods of View class.
int xCordinate = rulerLyt.findViewById(2).getX();
int yCordinate = rulerLyt.findViewById(2).getY();
If you call provided code just after view creation it will return 0. Because view inflation and measuring are async. They happen on different iterations of MainThread. You need to to use ViewTreeObserver as variant.
int[] locatoins = new int[2];
rulerLyt.findViewById(2).getLocationInWindow(locatoins);
float x = locatoins[0];
float y = locatoins[1];
imgBaby.setTranslationX(x);
imgBaby.setTranslationY(y);
Example of usage of ViewTreeObserver
view.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener(){
void onPreDraw(){
view.getViewTreeObserver().removeOnPreDrawListener(this);
//do your staff
return true;
}
})
I am developing an android application where I am creating dynamic Images arrow on relative layout. The images are created on a x,y coordinated of the click area of relative layout. Below is the code the I am using for it.
presciptionScreenArrowImg.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (canSelectMedianStatus == 2) {
if (event == simulationEvent)
return false;
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
Log.e("onTouchListener", "User touch at X:" + x + " Y:" + y);
pointerArrow = new ImageView(getApplication());
pointerArrow.setImageResource(R.drawable.pointer);
pointerArrow.setId(imageArrayTag);
imageArrayTag++;
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(40, 40);
params.topMargin = y;
params.leftMargin = x;
pointerArrow.setLayoutParams(params);
presciptionScreenArrowImg.addView(pointerArrow);
long length = 0;
if (action == MotionEvent.ACTION_DOWN) {
// click(v, x, y);
}
}
return false;
}
});
Now, I need is there on button click the last Image drawn should remove first. Basically I need an undo functionality to remove Images as LIFO structure.
let consider presciptionScreenArrowImg is your main layout which contains your all views so for removing
int index=presciptionScreenArrowImg.getChildCount();
if(index>0)
presciptionScreenArrowImg.removeViewAt(index-1);
from above get count of child and remove last view if you have any problem let me know
Store the views in a Queue, and when you add a new view check if the queue is full. If it is, pop a view from the queue, and call presciptionScreenArrowImg.remove(poppedView);
I know there are some similar topics that have been posted, but I couldn’t find a good solution for my problem.
I have a GridView which is filed with a custom ImageAdapter. Everything works fine, but whenever I click on an image contained in the GridView, I would like to move another Imageview at the click's position.
However, the coordinates of the Event, that I take with event.getX() and event.getY(), don’t correspond to the click’s position.
I first thought of a problem of dp/px conversion, and I tried several solutions in this way but none of them worked.
Then I tried to use the getXPrecision(), but I couldn’t make a working solution…
Maybe there is another way?
I would like to make the correct position programmatically, without adding constants int, so my project will work on various phone and tablet, with different dp and resolutions.
EDIT : Here is a screenshot, where i clicked the 3rd cell of the first line, and setted the position of the pencil with getRawX() - getRawY(). As we can see, this is not the correct position, I want the red dot (imageview's center) to be positionned where i clicked.
The code used :
//getting the position of the onTouch event :
GridView centre = (GridView) findViewById(R.id.gridView);
adapter = new ImageAdapter(this, (dim * dim), tailleCell);
centre.setAdapter(adapter);
centre.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View view, MotionEvent event) {
int X = (int)event.getRawX();
int Y = (int)event.getRawY();
animation(X, Y, etat);
return false;
}
});`
//launching the animation (and setting position of the pencil) :
private void animation(int posX, int posY, int etat)
{
final ImageView img;
if(etat == 0)
{
img = (ImageView) findViewById(R.id.imageView);
}
else
{
img = (ImageView) findViewById(R.id.imageView2);
}
img.clearAnimation();
img.setVisibility(View.VISIBLE);
img.setX(posX);
img.setY(posY);
[...]
}
EDIT 2 : ~Solution :
Jesus Molina Rodríguez De Vera's solution wasn't working as expected, but i managed to make a workable solution. I just changed my code in the Event Handler to adjust the image's position :
int[] offset = new int[2];
centre.getLocationOnScreen(offset);
int Xoffset=offset[0];
int Yoffset = offset[1];
int X = (int)event.getRawX();
int Y = (int)event.getRawY();
animation(X-((int)Math.round(Xoffset/1.15)), Y-((int)Math.round(Yoffset/1.5)), etat);
Sorry for my bad English :)
Thanks for your help!
Try using getRawX() and getRawY() instead of getX and getY.
Edit
I think that i have found the problem.
You are obtaining X and Y relative to the GridView top-left corner, not to the absolute screen coordinetes.
What you can do is the following:
int[] offset = new int[2];
center.getLocationOnScreen(offset);
int Xoffset=offset[0];
int Yoffset = offset[1];
private void animation(int posX, int posY, int etat){
//...
img.setX(posX+Xoffset);
img.setY(posY+Yoffset);
[...]
}
This is supposed to set the the top-left corner of the ImageView in the selected point. In order to set the center in that point:
int ivWidth = img.getWidth();
int ivHeight = img.getHeight();
private void animation(int posX, int posY, int etat){
//...
int[] finalPosition=new int[2];
finalPosition[0] = posX+Xoffset-(ivWidth/2);
finalPosition[1] = posY+Yoffset-(ivHeight/2);
img.setX(finalPosition[0]);
img.setY(finalPosition[1]);
[...]
}
I haven't try it but it should work.
Edit 2
Xoffset and Yoffset are only needed if you use getX()/getY() instead of getRawX()/getRawY()
I want to know how I can detect child views if I move a view from one ViewGroup to another ViewGroup, particularly when doing a touch event. Is there a method I can call that will let me know which views i'm "hovering" over?
What I'm doing right now is when I detect an ACTION_MOVE event on my view i'm raising it to the top level parent so that it can move and be drawn within the entire window ( and not just inside it's original parent bounds ), then I want to move the view across to a different ViewGroup and on ACTION_UP attach the view to that ViewGroup.
Inspired by Ami's response, but discovering that MotionEvent#getX()/getY() along with View#getTop()/etc return coordinates wrt the parent View, I ended up doing the following below to operate in screen coordinates, allowing me to work across ViewGroups:
private boolean inRegion(float x, float y, View v) {
v.getLocationOnScreen(mCoordBuffer);
return mCoordBuffer[0] + v.getWidth() > x && // right edge
mCoordBuffer[1] + v.getHeight() > y && // bottom edge
mCoordBuffer[0] < x && // left edge
mCoordBuffer[1] < y; // top edge
}
whose usage inside an OnTouchListener is e.g.:
boolean inside = inRegion(event.getRawX(), event.getRawY(), targetView);
I think I found a simpler way to do this.
Create an ArrayList of possible targets
Call this method from your touch event, supplying your targets list and the coords
private View findView(float x, float y, ArrayList<View> targets)
{
final int count = targets.size();
for (int i = 0; i < count; i++) {
final View target = targets.get(i);
if (target.getRight() > x && target.getTop() < y
&& target.getBottom() > y && target.getLeft() < x) {
return target;
}
}
return null;
}
I found Sebastian Roth's answer very helpful with resources, but since it wasn't really an answer to my question, I thought I'd share what I came up with.
Here is the code I use to detect views ( only views that will accept a drop that is ) given a coordinate on the screen.
private DropView findDropTarget( int x, int y, int[] dropCoordinates ){
final Rect r = mRectTemp;
final ArrayList<DropView> dropTargets = ((main) context).getBoardDropTargets();
final int count = dropTargets.size();
for (int i=count-1; i>=0; i--) {
final DropView target = dropTargets.get(i);
target.getHitRect(r);
target.getLocationOnScreen(dropCoordinates);
r.offset(dropCoordinates[0] - target.getLeft(), dropCoordinates[1] - target.getTop());
if (r.contains(x, y)) {
dropCoordinates[0] = x - dropCoordinates[0];
dropCoordinates[1] = y - dropCoordinates[1];
return target;
}
}
}
Ok, first off mRectTemp is just an allocated Rectangle so you don't have to keep creating new ones ( I.E. final Rect r = new Rect() )
The next line dropTargets is a list of views that will accept a drop in my app.
Next I loop through each view.
I then use getHitRect(r) to return the screen coordiantes of the view.
I then offset the coordiantes to account for the notification bar or any other view that could displace the coordiantes.
finally I see if x and y are inside the coordinates of the given rectangle r ( x and y are the event.rawX() and event.rawY() ).
It actually turned out to be simpler then expected and works very well.
Read this:
http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)
http://developer.android.com/reference/android/view/View.html#onTouchEvent(android.view.MotionEvent)
I had implemented a Drag and Drop using that method.
I also highly recommend a read of the HomeScreen sourcecode, which contains this thing (kind of):
https://android.googlesource.com/platform/packages/apps/Launcher2
I'm trying to implement scroll animation for gallery programmatically.
Tried with setSelection(int pos, Boolean animate) and it's not working.
Is there anyway to override setSelection() method.
Just now I have got this problem. I was need to move just one element of the gallery, so the best solution to me was to emulate key down event
myGallery.onKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT, null);
or
myGallery.onKeyDown(KeyEvent.KEYCODE_DPAD_LEFT, null);
Gallery.setSelection(int position, boolean animate);
Refer below URL:
http://groups.google.com/group/android-developers/browse_thread/thread/9140fd6af3061cdf/7f89e53ae53e455b?lnk=gst&q=setselection#7f89e53ae53e455b
Soln:
If you're still looking, I have two possible solutions for you, both
slightly unpleasant:
(1) You can make the gallery do a fling with a chosen velocity, thus:
myGallery.onFling(null, null, velocity, 0);
By tweaking the velocity, you can set up values to move the selection
by one or two in either direction. As the Gallery self-centers, you do
not need to get the destination exactly right.
(2) As the Gallery source is available, you can modify it in order to
implement your own Gallery. It doesn't look as though you need to add
much code to be able to control a fling so as to end at your chosen
selection.
I thought I was going to have to do (2), but found I could get away
with (1) for my problem.
Based on Kurru's excellent thinking of simulating clicking next or previous view.
//scroll forward or backward
private void scroll(int type){
View selectedV = mG.getSelectedView();
int idx = mG.indexOfChild(selectedV);
switch(type){
case FORWARD:
default:
if(idx<mG.getChildCount()-1)
idx++;
break;
case BACKWARD:
if(idx>0)
idx--;
break;
}
//now scrolled view's child idx in gallery is gotten
View nextView = mG.getChildAt(idx);
//(x,y) in scrolled view is gotten
int x = nextView.getLeft()+nextView.getWidth()/2;
int y = nextView.getTop()+nextView.getHeight()/2;
String out = String.format("x=%d, y=%d", x, y);
Log.i(TAG+".scroll", out);
//Kurru's simulating clicking view
MotionEvent event = MotionEvent.obtain(100, 100, MotionEvent.ACTION_DOWN, x, y, 0);
mG.onDown(event);
boolean res = mG.onSingleTapUp(null);
Log.i(TAG+".scroll", "onSingleTapUp return =" + res);
}
I was looking through the Gallery source to see if I could get this feature. It looks like something is possible with this code. However I gave up before I could get it working. It seems like I wasn't passing in the correct coordinates so res always returned false. Would return true if it worked.
Just posting this here in-case someone else wants to give a go at fixing it! (Please post your solution if you manage it!)
Rect rect = new Rect();
gallery.getHitRect(rect);
int x = rect.centerX()+getWindowManager().getDefaultDisplay().getWidth();
int y = rect.centerY();
MotionEvent event = MotionEvent.obtain(100, 100, MotionEvent.ACTION_DOWN, x, y, 0);
timesGallery.onDown(event);
boolean res = timesGallery.onSingleTapUp(null);
I made little change in code given by "Kurru". this is working now
Rect rect = new Rect();
gallery.getHitRect(rect);
int width = Math.abs(rect.width());
if(!isForwardScroll){
width = width * -1;
}
int x = rect.centerX()+width/2;
int y = rect.centerY();
MotionEvent event = MotionEvent.obtain(100, 100, MotionEvent.ACTION_DOWN, x, y, 0);
gallery.onDown(event);
boolean res = gallery.onSingleTapUp(null);