What I am having:
I am having a imageview on a linear layout. I want to detect
onTouch of imageview.
I do not want to use onClick because my implementation requires
onTouch Imageview is the child of linearLayout
What is happening:
Two touch events are firing when i click on image one from image and
another from the linear layout(parent)
Question:
How can I disable onTouch of linearLayout(parent)retaining the
onTouch of Imageview
Code:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
imgUsrClrId.setOnTouchListener(imgSourceOnTouchListener);
}
OnTouchListener imgSourceOnTouchListener= new OnTouchListener(){
#Override
public boolean onTouch(View view, MotionEvent event) {
Log.d("", "");
return true;
}};
Touch event is fired for only one view at a time, and here in your code touch event is fired for imageview but as we know touchListener will be called for every MotionEvent.ACTION_DOWN, MotionEvent.ACTION_UP, and MotionEvent.ACTION_MOVE. So if you want only one event to be fired at a time, ie MotionEvent.ACTION_DOWN or MotionEvent.ACTION_UP then write it in this way:
#Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action) {
// MotionEvent class constant signifying a finger-down event
case MotionEvent.ACTION_DOWN: {
//your code
break;
}
// MotionEvent class constant signifying a finger-drag event
case MotionEvent.ACTION_MOVE: {
//your code
break;
}
// MotionEvent class constant signifying a finger-up event
case MotionEvent.ACTION_UP:
//your code
break;
}
return true;
}
There are no multiple touch events generated from different views its all touch events from same ImageView I did test like below
Have a trace the viewID from which it
ImageView imageView = (ImageView) findViewById(R.id.imageView);
Log.i("Tag","ImageView ID :"+imageView.getId());
imageView.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
Log.i("Tag","OnTouch View ID :"+v.getId());
return true;
}
});
and when you return true from onTouch event will be consumed.
and here is output
ImageView ID :2131230721
OnTouch View ID :2131230721
OnTouch View ID :2131230721
OnTouch View ID :2131230721
Related
I am working on an Audio Recording App. It works in a way that when the user presses and moves the record button, the button moves along with the finger. I have created a boundary and when the finger crosses that boundary I want the button to perform the hide() animation and get back to it orginal position.
The whole process works fine if the MotionEvent.ACTION_UP or MotionEvent.ACTION_CANCEL event is occurred, but the hide() operation is not occurring even if the touch crosses the boundary. The button plays a back and forth motion sometimes when it is outside the boundary. The touch event is still being called even if I set the visibility of the view to false.
I get the output in the logcat as well (Log.e("MSG","boundary crossed");).
This is the code:
int recordButtonStartX;
microPhoneListner=new View.OnTouchListener() {
#Override
public boolean onTouch(View v, final MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
recordButtonStartX = (int) event.getX();
this.floatingRecordButton.display(event.getX());
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
this.floatingRecordButton.hide(event.getX());
break;
case MotionEvent.ACTION_MOVE:
int tempX = (int) event.getX();
if ((recordButtonStartX - tempX) > 200) {
Log.e("MSG","boundary crossed");
this.floatingRecordButton.hide(event.getX());
}
else
{
this.floatingRecordButton.moveTo(event.getX());
}
break;
}
recordMsgButton.setOnTouchListener(microPhoneListner);
To release the onTouchListener for any View set the listener to null.
recordMsgButton.setOnTouchListener(null);
or
After your condition satisfied you can set other listener to that View.
Make another listener
public final OnTouchListener mTouchListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent rawEvent) {
return false;
}
};
When you want to disable the listener then set other listener to that view
v.setOnTouchListener(mTouchListener);
If I touch down on a View, and then move passed its borders onto another View, the touch event ends (cancels). How can I continue processing the touch event on the next View without having to lift my finger up and retouch down onto the adjacent View, given that this is all happening within a ScrollView?
To prevent the ScrollView from scrolling when I move on the views, I have this system set up:
mScrollView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return mScrollingDisabled;
}
});
mTouchableView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
mScrollingDisabled=true;
break;
case MotionEvent.ACTION_CANCEL:
mScrollingDisabled=false;
break;
case MotionEvent.ACTION_MOVE:
mScrollingDisabled=true;
break;
case MotionEvent.ACTION_UP:
mScrollingDisabled=false;
}
return false;
}
});
I'm trying to catch the ACTION_UP and ACTION_CANCEL on my RecyclerView, but I want every other event to be caught by it's children, but it seems the child that caught the first event is the only one that catches all the following ones. Here my code for the intercept event.
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
boolean takeEventControl = false;
switch (e.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
takeEventControl = true;
break;
case MotionEvent.ACTION_MOVE:
// Some processing
takeEventControl = false;
break;
}
return takeEventControl;
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
// Some code
}
And here is my code for the child views
#Override
public boolean onTouch(final View view, final MotionEvent event) {
switch (e.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
//Some processing
break;
case MotionEvent.ACTION_MOVE:
//Some processing
break;
}
return true;
}
I already tested it and find that if I return true the first time the onInterceptTouchEvent is triggered the onTouchEvent is called successfully, but in my code I need to call the child onTouch when the event action is ACTION_DOWN or ACTION_MOVE, and the onTouchEvent on ACTION_UP or ACTION_CANCEL but the last one is never called, I hope someone could explain me what's happening here.
To avoid having a view control touches after the ACTION_DOWN, have all views return false in their onTouch for ACTION_DOWN. You can then return true for other touch events that are truly being handled.
The reason behind this is the first view to return true for ACTION_DOWN will be the only view to receive future onTouch calls until after an ACTION_UP or ACTION_CANCEL is received.
I have a simple Button, that has a touch listener. Once it's triggered on ACTION_DOWN action, a ListView appears on top of that button (so that the ListView is under user's finger).
What I want is to "pass" that touch event from Button to that ListView, so that when moved up/down, the list view would also scroll up/down.
Simply put:
User touches a Button
A list view appears on covering that button
WITHOUT RELEASING A FINGER, user starts moving finger to the top/bottom screen edge,
The list view scrolls.
UPDATE
I tried making a custom ListView component with onInterceptTouchEvent overridden, but I do not clearly get what should go into that method?
You should create a custom class extending ListView, then override the method onInterceptTouchEvent(MotionEvent e). That method gets called whenever a view inside the list is touched.
You don't need any custom component.
Set your button onTouchListener as:
button.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent)
{
switch (motionEvent.getAction())
{
case MotionEvent.ACTION_DOWN:
// popup the listView
break;
case MotionEvent.ACTION_MOVE:
// lstPopup is your ListView
lstPopup.dispatchTouchEvent(motionEvent);
break;
case MotionEvent.ACTION_UP:
// do other stuff
}
return false;
}
});
And set your listView onTouchListener as:
lstPopup.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_MOVE)
{
lstPopup.setSelectionFromTop(0, (int) motionEvent.getY());
}
return false;
}
});
I am trying to implement my own drag and drop with touch view events. I want to trigger dragging with long click, in onLongClick i create view shadow as bitmap and this bitmap is set to imageview. This imageview i want to drag. My problem is, that imageview is not responding to touch events immediately after that long click event. I have to stop touching screen and tap to imageview again and then my image is moving.
Some relevant code:
mCategoryNews.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
v.setVisibility(View.INVISIBLE);
ImageView shadow = (ImageView) getView().findViewById(R.id.imgViewShadow);
shadow.setLayoutParams(new FrameLayout.LayoutParams(v.getWidth(), v.getHeight()));
shadow.setImageBitmap(Utils.loadBitmapFromView(v));
shadow.bringToFront();
((FrameLayout.LayoutParams) shadow.getLayoutParams()).leftMargin = rowCategories1.getLeft();
((FrameLayout.LayoutParams) shadow.getLayoutParams()).topMargin = rowCategories1.getTop();
return true;
}
});
private View.OnTouchListener mDragShadowTouchListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d(TAG, "onTouch");
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "action move");
int x = (int) event.getRawX();//- rowCategories1.getLeft() - v.getWidth() / 2;
int y = (int) event.getRawY();//- rowCategories1.getTop() - v.getHeight();
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(mRowWidth / 2, mRowHeight);
params.setMargins(x, y, 0, 0);
v.setLayoutParams(params);
break;
case MotionEvent.ACTION_DOWN:
break;
}
return true;
}
};
no log output is present while i am still holding finger on screen after long tap.
This is a late answer, but I had a similar problem and found this solution:
Pass the MotionEvent to the view that should take it over via the dispatchTouchEvent method.
View myView = findViewById(R.id.myView);
#Override
public boolean onTouchEvent(MotionEvent event) {
myView.dispatchTouchEvent(event);
}
After the MotionEvent is passed, myView takes over and responds to new touch events.
If you return true in onLongClick() it means the callback has consumed the event and thus it is not propagated further. If you return false, then it will reach down to the child views. (I assume the touch listener is set on the shadow ImageView).
I believe to delegate try returning false