PROBLEM
I have a horizontalListView that is showing user all the images loaded to ViewPager. Its situated on the bottom of the screen.
What I want to do is for horizontalListView to hide when its not being used for more then 5 sec.
How it should work:
User taps screen horizontalListView appears
User scrolls, selects do stuff on horizontalListView and its blocking threads to be fired
After 5 sec of doing nothing on horizontalListView, it disappears
How its working right now:
User taps screen horizontalListView appears
User scrolls, selects ect. and postDelayed is getting fired making my horizontalListView dissappear.
CODE
HorizontalListView and Runnable
horizontalListView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
hideViewHandler.removeCallbacks(mRunnable);
hideViewHandler.postDelayed(mRunnable,5*1000);
return true;
}
});
mRunnable = new StoppableRunnable() {
#Override
public void stoppableRun() {
hideAnimation();
}
};
TapListener that is set on Image responsible for showing horizontalListView
private class TapGestureListener extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
hListView.clearAnimation();
if (((ViewGroup.MarginLayoutParams) hListView.getLayoutParams()).bottomMargin < 0) {
expandAnimation();
hideViewHandler.postDelayed(mRunnable,5*1000);
} else {
hideAnimation();
}
return true;
}
}
You have to check inside the listener for the MotionEvent.ACTION_UP or MotionEvent.ACTION_CANCEL to only trigger the runnable after them.
Your current code is posting the runnable on any event, but you want to do it only when the user has stopped using the view.
BTW: If you return true from the TouchListener it means that you have consumed the event and the event chain will stop. Most likely the ScrollView will not even scroll, since the event will not be propagated to it.
You can do something like this..
yourScreenLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (horizontalListView.getVisibility() == View.INVISIBLE) {
horizontalListView.setVisibility(View.VISIBLE);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (horizontalListView.getVisibility() == View.VISIBLE)
horizontalListView.setVisibility(View.INVISIBLE);
}
}, 5000);
} else {
horizontalListView.setVisibility(View.INVISIBLE);
}
}
});
I think the source of you problem might be calling removeCallbacks before postDelayed.
The thread itself is fired after u clear the queue.
I have managed to fix the problem myself.
FIX
The main reason why my onTouchListener did not work as intended was that it had not been triggered at all. OnClickListener inside horizontalListView adapter was consuming the trigger.
Now I am passing the info that the click occurred inside onClickListener and do all the things in different method.
Related
I could see that the animation when tapping on a button starts after the stuff in the onClick method finished and was wondering if this is an Android bug or normal behaviour?. I could find a few posts (this one e.g.) about people searching how to start something after the animation ended, so I am not alone I suppose, but I don't think this is logic at all?
YouButton. setOnTouchListener(
new View.OnTouchListener() {
public boolean onTouch(View myView,
MotionEvent event) {
int action = event.getAction();
if (action==MotionEvent.ACTION_UP)
{
//after animation
}
if (action==MotionEvent.ACTION_DOWN)
{
//your animation
}
return true;
}
}
Anyone have a work around to get this set up? I have a spinner in my action bar where I'd like to capture a long click event, either OnLongClickListener, or for the individual item OnItemLongClickListener - so the user can edit the value.
I've read that spinner doesn't support long clicks, but I was hoping that something might have changed/someone might have a workaround.
It's the ideal solution for editing the string - there's not enough space in the action bar to put a dedicated button for editing, and my users intuitively try to long press to edit.
Here are some related questions (although quite old now):
Android spinner item long click/touch,
How can I use spinner setOnItemLongClickListener
You should be able to "simulate" a long click with the following code:
final Handler actionHandler = new Handler();
final Runnable runnable = new Runnable() {
#Override
public void run() {
Toast.makeText(Activity.this, "Long click performed", Toast.LENGTH_SHORT).show();
}
};
spinner.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
actionHandler.postDelayed(runnable, 1000);
} else if(event.getAction() == MotionEvent.ACTION_UP){
actionHandler.removeCallbacks(runnable);
}
return false;
}
});
Yo can play around with the time in order to get a more "real" feeling, but that's pretty it i believe.
I hope it helps
I am trying to make some field with text (no button) what I click on to open datepicker dialog.
I am totally begginer and I am trying it on easy example.
firstbirth.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Toast.makeText(getApplicationContext(), "ahooj", Toast.LENGTH_LONG).show();
return false;
}
});
firstbirth is spinner, I tried it with Edittext and the result was same.
Can anybody help me?
Thanks in advance!
Use an OnClickListener instead.
setOnClickListener(View.OnClickListener l)
OnTouchListeners will trigger on multiple touch events (like touch down, touch up etc.) whereas the OnClickListener will only get fired once (onClick :) )
If you, for some reason, want to use an OnTochListener you can make sure that its only called once.
Try:
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_UP { // another option would be ACTION_DOWN for example
Toast.makeText(getApplicationContext(), "ahooj", Toast.LENGTH_LONG).show();
return true;
}
return false;
}
Thanks it sounds logical but when I use OnClick event application felt down while initializing.
firstbirth.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DialogFragment dd1 = new DatePickerFragment();
dd1.show(getFragmentManager(), "Select a date");
}
});
Problem is not with DialogFragment becasue it works when I use onTouch event.
Thanks :)
I'm using an opensource numberpicker I found somewhere (credit to Jeffrey F. Cole) but I just found a bug.
The numberpicker has a handler to increase the number faster when you touch the button
long`private Handler repeatUpdateHandler = new Handler();
`
class RepetetiveUpdater implements Runnable {
public void run() {
if (autoIncrement) {
increment();
repeatUpdateHandler.postDelayed(new RepetetiveUpdater(),
REPEAT_DELAY);
} else if (autoDecrement) {
decrement();
repeatUpdateHandler.postDelayed(new RepetetiveUpdater(),
REPEAT_DELAY);
}
}
}
.....
public class NumberPicker extends LinearLayout {
.....
// Auto increment for a long click
increment.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View arg0) {
autoIncrement = true;
repeatUpdateHandler.post(new RepetetiveUpdater());
return false;
}
});
// When the button is released, if we're auto incrementing, stop
increment.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP && autoIncrement) {
autoIncrement = false;
}
return false;
}
});
The problem is when you longclick the button the counter starts to increase, but when you hold your finger down and drag your finger across the screen the counter keeps adding up, even when you lift your finger.
So how can I detect that the finger gets out of my numberpicker layout and stop the counter?
Thx :)
I'm not so sure that's a bug and I'm not even sure it's coming from changes that this number picker made on top of the numberpicker from the API itself. I'm assumings that the buttons that handles incrementing and decrementing the pickers are set up to keep going until an ACTION_UP MotionEvent is received, but this might be over-simplifying it.
EDIT:
I've tested this on stock Android 2.3.3 and this is precisely the result.
EDIT:
Based on your clarification in the comments, this does sound like a pretty bad bug. Looks like what you need to do is have the Handler removes the callbacks to that runnable in ACTION_UP. Can you link me to the project so I can try to submit a patch?
EDIT
The NumberPicker you provided wasn't using Handlers correctly, IMO. Instead of keeping a reference to the same Handler so that callbacks could later be removed, it was created a new one everytime it posted. I've made some changes and fixed the issues here: https://gist.github.com/3657989
When application is started I run a custom pop-up till a user touches the screen. When screen is touched I catch it with event onTouch() and cancel the pop-up. From this point I don't need the event anymore.
The problem is the event is alive and continues to jump up every time a user touches the screen.
Is there any way to unsubscribe from this event? Something like in c# -= eventName.
The code is below:
#Override
public boolean onTouch(View v, MotionEvent event) {
if (!_stopToast)
{
_hintToast.cancel();
_stopToast = true;
}
return false;
}
There's no such method (lets say removeTouchListener or similar) which will help you to remove an already defined touch listener from a view. Setting null to setOnTouchListener won't help too. What you can do is to create a new object reference of OnTouchListener class which does nothing and set it in setOnTouchListener. For example:
public final OnTouchListener dummyOnTouchListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent rawEvent) {
return false;
}
};
And simply use it as below:
yourView.setOnTouchListener(dummyOnTouchListener);