Android :: OnTouchListener && OnClickListener combination issue - android

Problem description:
I have a TextView on a RelativeLayout and I want to color it red when the user touches it, and go on another page when he clicks on it.
So I tried to set an OnClickListener to do the click, and an OnTouchListener to implement the touch function (MotionEvent.ACTION_DOWN) but this combination doesn't work, because OnTouchListener makes OnClickListener non-functional (don't know why).
On forums people say that we can implement the OnClick by the OnTouch MotionEvent.ACTION_UP, but this one can be triggered out of my TextView layout (the TextView gonna be clicked if you press it and drag your finger out of him to release) and this is not the desired behavior because I want:
click = press + release on the TextView.
Can someone give me a solution for this please?

you may call View.performClick() when action_up. Hope it helps.
your_txtView.setOnClickListener(new TextView.OnClickListener(){
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
your_txtView.setOnTouchListener(new TextView.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
if (MotionEvent.ACTION_DOWN == event.getAction()) {
} else if (MotionEvent.ACTION_UP == event.getAction()) {
v.performClick();
}
return true;
}
});

Adel, is the problem with the first click, or you don't get any click at all?
There is this issue if you have multiple clickable layout you don't get any click events for the first. That's because it makes it first selected and then you get the click event, try the below code.
private class CustomTouchListener implements OnTouchListener {
#Override
public boolean onTouch(View v, MotionEvent event) {
TextView tv = (TextView) v.findViewById(R.id.single_line_text);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
tv.setTextColor(COLOR_WHEN_PRESSED);
} else if (event.getAction() == MotionEvent.ACTION_UP) {
tv.setTextColor(COLOR_WHEN_RELEASED);
// Action of click goes here
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
tv.setTextColor(COLOR_WHEN_RELEASED);
// To handle release outside the layout region
}
return false;
}
}
This is working in my current implementation if you set the touch listener for your layout.
You also need to set below on your layout
android:focusable="true"
android:focusableInTouchMode="true"
android:clickable="true"
Hope it helps!!!
EDIT: Additionally, there should be a flag in both DOWN and UP. Set it in DOWN and check if its set in UP. This will avoid a bug where user might tap anywhere in the screen and then hover on your textview and release it.

Had the same problem. Solved it by returning false from ACTION_MOVE. I've been fighting with it for few hours, trying various things, but seems like i've kept overlooking this little issue... And now it makes sense. When you return true from onTouch, futher processing is stopped, so that OnClickListener is not aware of any movements and triggers onClick even after pointer have moved outside of view.

Related

Android - Pressed / Touched item in a ListView

Is it possible to know in a ListView if a item is pressed / touched (but not clicked) and know which?
I tried with "OnTouchListener" but without success (I can intercept UP and Down events on the ListView but not on the elements).
I tried also "OnItemLongClickListener" but I have to wait when I want information immediately.
Do you have an idea ?
Thank you in advance.
Edit (solution) :
I put the following code in my adapter in the item view.
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
image.setImageResource(R.drawable.image2);
}
else if (event.getAction() == MotionEvent.ACTION_UP) {
image.setImageResource(R.drawable.image1);
}
return true;
}
});
And now, when I touch an item, the picture becomes "image2" and when I do not touch the screen, it returns to "image1".
But there is a problem, if I press an item (the image2 appears well) and I move my finger in the list view and I do not touch the screen, it stays on for the image2, "MotionEvent.ACTION_UP" could not execute.
Do you have any idea how to do that as soon as I do not touch the screen, it must return on image1?
Thank you for your help.
You can set SetOnTouchListener to item view when your adapter create it.
you just try yo implement the Listener then you can override the function or please add your rough work part

Android On Focus Listener and On Click Listener on ImageView

I have an imageview - It has both the attributes -focusable and focusableintouchmode set to true
<ImageView
android:id="#+id/ivMenu01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:focusable="true"
android:focusableInTouchMode="true" >
</ImageView>
I have implemented the onFocusChangeListener in my activity-
#Override
public void onFocusChange(View v, boolean hasFocus) {
switch (v.getId()) {
case R.id.ivMenu01:
if (hasFocus) {
ivMenu01.setImageBitmap(Utility
.getBitmap("Home_ford_focus.png")); // Focussed image
} else {
ivMenu01.setImageBitmap(Utility.getBitmap("Home_ford.png")); // Normal image
}
break;
default:
break;
}
}
Also the onClickListener -
case R.id.ivMenu01:
ivMenu01.requestFocus();
Intent iFord = new Intent(HomeScreen.this, FordHome.class);
startActivity(iFord);
break;
Now when i click the ImageView the first click gives the focus to the ImageView and the second click performs the action.
I am not sure why this is happening .
The first click should request focus as well as perform the action.
Any help on how to do this will be highly appreciated.
It's the way the widget framework is designed.
When you look at View.onTouchEvent() code, you'll find out that the click action is performed only if the view has taken focus:
// take focus if we don't have it already and we should in
// touch mode.
boolean focusTaken = false;
if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
focusTaken = requestFocus();
}
if (!mHasPerformedLongPress) {
// This is a tap, so remove the longpress check
removeLongPressCallback();
// Only perform take click actions if we were in the pressed state
if (!focusTaken) {
// click
}
}
So, as you noticed, the first click makes the view gain focus. The second one will trigger the click handler since the view already has focus.
If you want to alter the bitmap of the ImageView when it's pressed, you should implement an View.OnTouchListener and set it via ImageView.setOnTouchListener() method. That listener should look more or less like this:
private View.OnTouchListener imageTouchListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// pointer goes down
ivMenu01.setImageBitmap(Utility.getBitmap("Home_ford_focus.png"));
} else if (event.getAction() == MotionEvent.ACTION_UP) {
// pointer goes up
ivMenu01.setImageBitmap(Utility.getBitmap("Home_ford.png"));
}
// also let the framework process the event
return false;
}
};
You can also use a Selector aka State List Drawable to achieve the same thing. See reference here: http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList

Android - Button OnTouch event change focus of Button

I have an App with 10 Buttons. Everytime the User presses on one Button A TextView should change. And if the User changes the focus and ,oves its finger to right, to the next button(without taking the finger off the screen) the seond button should be focused.
I tried it with setting an OnTouchListner to all buttons, but once the finger is moved the focus still stays on the first button:
btn1.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
txt1.settext("1");
return false;
}
});
I hope you understood what I mean and can help me with this.
Thanks
Edit:
I found an Application which does that, here is a Video, so you can visualise what I mean.
Notice how I move the mouse(the finger in this case) and the Boxes change its focus:
http://www.youtube.com/watch?v=MRVFpNrBmsA&feature=youtu.be
To start in your onTouch() you should handle the events...
Something like
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
txt1.settext("1");
} else if(event.getAction() == MotionEvent.ACTION_HOVER_EXIT){
txt1.settext("0");
}
return true;
}
Not sure if those are the proper actions to check against but it is just to give the idea.
Also I believe you should return true otherwise it means that the event wasn't processed and it gets stuck.

how do i make different touch and click behaviours for buttons?

Im working on an app with a friend and i want the button to visually press by changing the background and vibrating and then when released it does whatever that button is supposed to do.
the buttons i have right now only have an onclick method but i want it vibrate when touched and execute their function when clicked
i know of the ontouch and onclick methods but i cant seem to use them togetherand have already implemented both onclicklistener and ontouchlistener
how might i manage this.
You could do this by only using the OnTouchListener:
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
/* Change your button background and vibrate */
}
else if (event.getAction() == MotionEvent.ACTION_UP) {
/* Button's functionality */
}
return true;
}
Hope it helps.

Overriding onTouchEvent competing with ScrollView

From a simplistic overview I have a custom View that contains some bitmaps the user can drag around and resize.
The way I do this is fairly standard as in I override onTouchEvent in my CustomView and check if the user is touching within an image, etc.
My problem comes when I want to place this CustomView in a ScrollView. This works, but the ScrollView and the CustomView seem to compete for MotionEvents, i.e. when I try to drag an image it either moves sluggishly or the view scrolls.
I'm thinking I may have to extend a ScrollView so I can override onInterceptTouchEvent and let it know if the user is within the bounds of an image not to try and scroll. But then because the ScrollView is higher up in the hierarchy how would I get access to the CustomView's current state?
Is there a better way?
Normally Android uses a long press to begin a drag in cases like these since it helps disambiguate when the user intends to drag an item vs. scroll the item's container. But if you have an unambiguous signal when the user begins dragging an item, try getParent().requestDisallowInterceptTouchEvent(true) from the custom view when you know the user is beginning a drag. (Docs for this method here.) This will prevent the ScrollView from intercepting touch events until the end of the current gesture.
None of the solutions found worked "out of the box" for me, probably because my custom view extends View, not ViewGroup, and thus I can't implement onInterceptTouchEvent.
Also calling getParent().requestDisallowInterceptTouchEvent(true) was throwing NPE, or doing nothing at all.
Finally this is how I solved the problem:
Inside your custom onTouchEvent call requestDisallow... when your view will take care of the event. For example:
#Override
public boolean onTouchEvent(MotionEvent event) {
Point pt = new Point( (int)event.getX(), (int)event.getY() );
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (/*this is an interesting event my View will handle*/) {
// here is the fix! now without NPE
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(true);
}
clicked_on_image = true;
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (clicked_on_image) {
//do stuff, drag the image or whatever
}
} else if (event.getAction() == MotionEvent.ACTION_UP) {
clicked_on_image = false;
}
return true;
}
Now my custom view works fine, handling some events and letting scrollView catch the ones we don't care about. Found the solution here: http://android-devblog.blogspot.com.es/2011/01/scrolling-inside-scrollview.html
Hope it helps.
There is an Android event called MotionEvent.ACTION_CANCEL (value = 3). All I do is override my custom control's onTouchEvent method and capture this value. If I detect this condition then I respond accordingly.
Here is some code:
#Override
public boolean onTouchEvent(MotionEvent event) {
if(isTouchable) {
int maskedAction = event.getActionMasked();
if (maskedAction == MotionEvent.ACTION_DOWN) {
this.setTextColor(resources.getColor(R.color.octane_orange));
initialClick = event.getX();
} else if (maskedAction == MotionEvent.ACTION_UP) {
this.setTextColor(defaultTextColor);
endingClick = event.getX();
checkIfSwipeOrClick(initialClick, endingClick, range);
} else if(maskedAction == MotionEvent.ACTION_CANCEL)
this.setTextColor(defaultTextColor);
}
return true;
}

Categories

Resources