I have implemented swipe behavior in my list view. So, basically, you can drag a item and item's alpha value would change accordingly (thanks to code by Roman Nurik Roman Nurik & Tim Roes). The application is doing fine. Basically, on a generic list item, touch is treated as click, so for list without dragging facility, do not find difference between the two. But in my case, since I detect the co-ordinate at onTouch() to judge whether the user is scrolling left to right or right to left. My list does makes a difference between touch and click. So, I want to know do I dispatch a click event manually on list item so that even if user has not clicked and has dragged the item on touch, i still get to call OnListItemClick().
Thanks.
Long time, no reply given.
Anyway, I thought to share my own findings on this question.
I found that there is no way of dispataching an event manually as far as I know. But I found that I could handle my problem in another way. Here is how I handled it.
public boolean onTouch(View v, MotionEvent event) {
if(v.isPressed()
//
}
isPressed() would return when view is in pressed state. When it returns true, you can proceed further.
Hope it helps someone else.
Related
in iOS world, there's a concept of touchUpInside, touch started within a view and user lifted a finger within a view bound.
I see touch vs click (event listeners) in android, and I'd like to know the difference between them.
Touch events are much more basic. There's many varieties. The most common being:
DOWN: The user touch the item
MOVE: The user shifts around the item after touching it
UP: The user stops touch the item
CANCEL: The user shifts off the item but is still touching the screen.
In Android, a click event is a composite of touch events. In the case of click it's both DOWN and UP action. There are others that can be found in a GestureDetector. Fling for example is a combination of DOWN, MOVE, and UP in a fast motion that signifies the user swiped the finger really fast.
EDIT:
Clarification on how Android handles the true and false in onTouchEvent().
It's not very well documented, but the way the Views work in Android is that when you touch a View, it will send that touch event from the parent view to all children views. Each child will then send the event to it's children. This is done in the dispatchTouchEvent() method.
When a parent View receives false from the child's onTouchEvent() method, it will no longer send touch events to that child. Meaning that when you're view returns false in onTouchEvent(), your View is really says:
I am done processing touch events and all of my children are done as well.
90% of the time, in onTouchEvent() you would do return super.onTouchEvent() to return the touch values of all the children in the View.
So let's look at your click example. Here's one way to do it in which you return false on a DOWN event, but true on an UP.
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
return false;
case MotionEvent.ACTION_UP:
return true;
break;
default:
return false;
}
}
In this case, the parent of this View will receive false immediately. After which, it will stop sending touch events to this View because you said it was done.
Here's another way:
boolean mPossibleClick = false;
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPossibleClick = true;
break;
case MotionEvent.ACTION_UP:
if(mPossibleClick) {
// UP event immediately after DOWN. Perform click action
}
default:
mPossibleClick = false;
}
return mPossibleClick;
}
It's rather crude, but basically here's what will happen. When the user first touches it, you will receive DOWN which will return true. If the user lifts the finger, it will perform a click action after which will return false because the event is done. If the user moves his finger or any other action is performed, it will return false and the click will be nulled out.
That last one is not the best way to implement a click, but I think it illustrates what I'm trying to say. In real life, move events are extremely common if even for a couple pixels.
onClickListener is used whenever a click event for any view is raised, say for example: click event for Button, ImageButton.
onTouchListener is used whenever you want to implement Touch kind of functionality, say for example if you want to get co-ordinates of screen where you touch exactly.
Definitions:
onClickListner: Interface definition for a callback to be invoked when a view is clicked.
onTouchListener: Interface definition for a callback to be invoked when a touch event is dispatched to this view. The callback will be invoked before the touch event is given to the view.
Details:
onClickListener: http://developer.android.com/reference/android/view/View.OnClickListener.html
onTouchListener: http://developer.android.com/reference/android/view/View.OnTouchListener.html
refer to the response of PH7
which one is better to use?
It really depends on your requirement.
onTouch gives you Motion Event. Thus, you can do a lot of fancy things as it help you separate state of movement. Just to name a few
ACTION_UP
ACTION_DOWN
ACTION_MOVE
Those are common actions we usually implement to get desire result such as dragging view on screen.
On the other hand, onClick doesn't give you much except which view user interacts. onClick is a complete event comprising of focusing,pressing and releasing. So, you have little control over it. One side up is it is very simple to implement.
do we need to implement both?
It is not necessary unless you want to mess up with your user. If you just want simple click event, go for onClick. If you want more than click, go for onTouch. Doing both will complicate the process.
From User point of view, it is unnoticeable if you implement onTouch carefully to look like onClick.
for more details : refer this and this
In a ListFragement I want to display additional edit options next to an item after the user long-clicks onto it.
This works fine using the following code in a custom ArrayAdapter (inside getView):
rowView.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View v) {
//Show the edit controls
View editArea = rowView.findViewById(R.id.editArea);
editArea.setVisibility(View.VISIBLE);
//Don't raise additional events for this touch
return true;
}
});
However, my problem is which event to use in order to hide those additional edit controls.
Ideally, when the edit controls are displayed, any touch outside them should be ignored in favor of hiding them (a little bit like when a dialog is opened and the user clicks somewhere besides it).
I tried overwriting dispatchTouchEvent in my MainActivity - if I generally intercept all ACTION_DOWN events, however, my edit controls are hidden before the click is dispatched to them (of course).
Is there any possibility to detect which control the user has touched without already dispatching the event?
If I intercept all ACTION_UPs, the edit-controls are removed when the user ends their long-click. And I am trying to avoid whether a specific ACTION_UP belongs to the long touch as this would produce some really messy code.
Any ideas which event to listen to?
Or do you know any better, alternate way to achieve my goal?
So I have an interesting problem. I have a ListView that I want to maintain the exact row selection and yoffset on an orientation change. As such I call:
list.postDelayed(new Runnable() {
#Override
public void run() {
list.requestFocusFromTouch();
list.setSelectionFromTop(finalPosition, yoffset);
}
},100);
Seems pretty straightforward and it works well. The problem is that when I change the orientation twice (get back to the original orientation, ie landscape->portrait->landscape) than the list has exited TouchMode, ie list.isInTouchMode() returns false (On the first orientation change, list.isInTouchMode() returns true and everything is great, clicking works etc). As such when you scroll the listview programatically using setSelectionFromTop() and click on an item in the list without touching somewhere else in the app first, the list jumps and scrolls to where I clicked, highlighting the wrong item. It's very annoying and I can't seem to find a fix for it. Any ideas and suggestions are most welcome.
Calling list.requestFocusFromTouch() seems to have no effect on setting TouchMode.
More info:
Android:To set an item as selected when the ListView opens?
I found a post from Romain Guy "Whenever you touch the screen, anywhere in the phone, you enter touch
mode for all of the applications. This is the desired and expected
behavior. " http://groups.google.com/group/android-developers/browse_thread/thread/590b02939d14675b/077ad77e4217e56e?lnk=gst&q=[android]+scroll+listview+not+in+touchmode#077ad77e4217e56e
All i want to do is somehow get into TouchMode without forcing the user to actually touch the device on the second orientation change. I have tried list.dispatchTouchEvent() multiple times. Its possible I am sending the wrong motion events:
list.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN ,
list.getWidth(), list.getHeight(), 0));
list.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE ,
list.getWidth(), list.getHeight(), 0));
list.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), MotionEvent.ACTION_UP ,
list.getWidth(), list.getHeight(), 0));
Another option would be to figure out why we are no longer in TouchMode. I have not overriden onConfigurationChanged() so the layout is completely rebuilt on each orientation change.
Thanks in advance!
Jared
Try using setItemChecked(...) method of the Listview. I've seen that used a fair bit when the Listview is set to CHOICE_MODE_SINGLE, as that mode really makes each listview item a checkable object.
Also look at the following QA where someone was trying to do something similar. It appears that the easiest solution was to create a different background for 'checked' items.
Android listview array adapter selected
This question is a bit awkward. Is it possible to transfer the touch focus of one view to another? Basically, say that you have a view that picks up the first ACTION_DOWN touch event, and then immediately wants to transfer the focus for all touch events to another view to handle with it's onTouchEvent(MotionEvent event). I thought that doing the following would make it work, but it didn't:
#override
public boolean onTouchEvent(MotionEvent) {
this.clearFocus();
anotherView.setFocusableInTouchMode(true);
anotherView.requestFocus();
}
Obviously, it seems to me that it just doesn't work that way. Could someone explain to me how I can go about doing something like this?
If it's still a bit difficult to understand my question, think about a regular button. When pressed, the button is highlighted (focused) and if you move your finger off the button but still keep your finger on the screen, the button becomes unfocused but still has control of the entire touch events (no other view can become focused even if you move over them). My question asks if it is possible to transfer this touch focus to another view to handle without having you to remove your finger off the screen.
Try below code might work
button1.setOnFocusChangeListener(new OnFocusChangeListener()
{
#Override
public void onFocusChange(View arg0, boolean hasFocus)
{
if(hasFocus)
button2.requestFocus();
}
});
The way I worked around this was to have a single view "harness" whose sole purpose was to pass on the touch information to the other classes, who would then do the processing. Note that ViewA and B don't actually have to be views and extend the view class. Its not an ideal solution, but I don't think it's possible to solve this problem with the current Android framework (ICS/JB).
class ViewHarness extends View{
public boolean onTouch(MotionEvent event){
if(ViewA is selected)
ViewA.onTouch(event);
else
ViewB.onTouch(event);
}
I am using table layout to display data, but i want it to behave like list items
(ability to select, when select change background, when click, having hover effect, click able) for that purpose i am using following listeners
OnClickListener(to perform action)
OnFocusChangeListener(To change background color)
OnTouchListener(to focus specific row)
Now problem is when user touch any item it get focus first and then have to touch again to fire onclick event, to fix this i made a change and ontouch i fire action on specific to row.
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_UP){
v.requestFocus();
int viewId= v.getId();
handleEvent(viewId);//Switch cases to perform row specific actions.
}
return false;
}
now if user touch the row event get fired that works perfect, But one more problem rises here when even user want to scroll down the data via dragging finger onto the screen ontouch event get fired.... and action automatically performed although user think it will scroll down the screen.
I don't know if this solution is applicable in your case, but maybe you can do like this:
Let's assume that user clicked your item (so probably you will get sequence of three events to your OnTouch() method: ACTION_ DOWN, ACTION_ MOVE (not necessarily) and ACTION_UP. Now you can react accordingly.
If it's ACTION_DOWN, you can save x and y coordinates.
If it's ACTION_ MOVE, take its x and y and calculate the distance from corresponding ACTION_DOWN. If it's longer than some assumed value, then make the scroll and set the flag indicating that items were scrolled.
If it's ACTION_UP check your flag. If items were not scrolled, fire your action and clear the flag.
Probably calculations is not what you should do in ACTION_MOVE event, because it should be fast, but give it a try.
Regards!