I have a ViewFlipper and in it, four scrollviews with layouts in those.
I use the following code (for each scrollview) to swipe:
ScrollView View1 = (ScrollView) findViewById(R.id.View1);
View1.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if (event.getAction() == MotionEvent.ACTION_DOWN) {
FirstX = (int) event.getX();
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
int LastX = (int) event.getX();
if (FirstX - LastX > SWIPE_MIN_DISTANCE) {
viewFlipper.setInAnimation(slideLeftIn);
viewFlipper.setOutAnimation(slideLeftOut);
viewFlipper.showNext();
} else if (LastX - FirstX > SWIPE_MIN_DISTANCE) {
viewFlipper.setInAnimation(slideRightIn);
viewFlipper.setOutAnimation(slideRightOut);
viewFlipper.showPrevious();
}
}
return true;
}
});
It works, but it looks like if I swipe from View 1 to View 2, I see a views 2 and 3 mixed together and it finally shows view 4.
So it seems the OnTouchListeners for each view are called after eachother.
How can I prevent this from happening?
A short and fast swipe does what it is supposed to do.
rg,
Eric
You should move your code you have in MotionEvent.ACTION_MOVE to MotionEvent.ACTION_UP to get a swipe. Now, if you don't want swipe, and want to move the screen along with the finger, you should implement ViewPager as JafarKhQ just mentioned.
the setOnTouchListener will called multible time (while you sliding your finger), so the
viewFlipper.setInAnimation(slideLeftIn);
viewFlipper.setOutAnimation(slideLeftOut);
viewFlipper.showNext();
will called multiple time
i suggest you to use the ViewPager instead of ViewFlipper.
Related
I have a list view and I want to make it so I can swipe each item to reveal a delete button:
I've figured out how to recognise the swipe event, I am using this code (listItem is of type View):
listItem.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event)
{
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
_xSwipe1 = event.getX();
break;
case MotionEvent.ACTION_UP:
_xSwipe2 = event.getX();
float deltaX = _xSwipe2 - _xSwipe1;
if (deltaX < 0)
{
Log.e("SWIPE", "Right to Left swipe");
}
else if (deltaX >0)
{
Log.e("SWIPE", "Left to right swipe");
}
break;
}
return false;
}
});
And when I swipe, I can see in the logs that the swipe event is being recognised.
However, I'm not sure how to physically make the list item start disappearing to the left?
Any help would be greatly appreciated.
If you know when the swipe is happening and how much the user has swiped you could call View.setTranslationX() depending on how much the user has swiped. Alternatively, you could forego the swipe detection logic altogether and use a ViewPager with only 2 pages. You would then override PagerAdapter.getPageWidth(...) in your PagerAdapter so that the delete button only takes up a limited amount of space.
I'm using an on touch listener to display and hide some volume controls, on ACTION_DOWN the controls are displayed and on ACTION_UP they are hidden. I want to be able to touch the controls without lifting my finger, I tried using the ACTION_MOVE motion and was unable to get it to work as the event is never triggered. I thought about drag event but I am unsure if it would be appropriate for this.
public boolean onTouch(View v, MotionEvent e)
{
if(v == audioControls)
{
if(e.getAction() == MotionEvent.ACTION_DOWN)
showVolumeControls();
else if(e.getAction() == MotionEvent.ACTION_UP)
hideVolumeControls();
}
else if(e.getAction() == MotionEvent.ACTION_MOVE)
{
if(v == mute)
//Do stuff with this volume control
}
return true;
}
#Demand answer, read my comment - here is the code:
public boolean onTouch(View v, MotionEvent e)
{
if(v == mute && e.getAction() == MotionEvent.ACTION_MOVE)
{
Toast.makeText(getApplicationContext(), "Muted.", Toast.LENGTH_SHORT).show();
hideVolumeControls();
return true;
}
else
return false;
}
So, you need to uderstand how android touch events work. If you touch down on View1, set onTouchListener for that view and return true for that event - other view will never get motion events from same chain.
For you it's mean that if you touch down on "audioControls" then no other views can catch motion events until you release your finger.
You can return false in your onTouch method. In this case parentView for audioControls will also catch all motionEvents. But views, which is not parent for audioControls in the view hierarchy will not catch motionEvent.
You need to catch all motion events in the container for your views and dispatch them for your self. This is the only way to catch motionEvents from one chain in defferent views.
UPDATE:
I will try to explain a little bit more.
Imagine you have layout like this:
<LinearLayout id="#+id/container">
<View id="#+id/view1"/>
<View id="#+id/view2"/>
</LinearLayout>
And you want to touch down on view1 and move your finger to view2. Android touch event flow can't do this. Only one view can catch whole event chain.
So you need to add onTouchListener to your container and do something like this.
public boolean onTouch(MotionEvent event) {
float x = event.getX();
float y = event.getY();
for (int i = 0; i<container.getChildCount(); i++) {
View child = container.getChildAt(i);
if (x>child.getLeft() && x < child.getRight() && y < child.getBottom() && y > child.getTop()) {
/*do whatever you want with this view. Child will be view1 or view2, depends on coords;*/
break;
}
}
}
Please note, I wrote this code right there and could make some mistake. I've tried to show the idea.
I have a list View in my Main Activity, which contains a list of full size images. i am trying to implement onTouchListener on that image view of list view to get the points where user touched. and i am getting it correct by implementing onTouchListener in get View method of Custom Adapter for list view. but when i touch screen for scrolling list it still gives me the points while scrolling the list. but i don't want to get onTouchListener called while scrolling the list. How can i do this.
you may try this, this might work
float posX, posY;
imageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN){
posX = event.getX();
posY = event.getY();
}
if (event.getAction() == MotionEvent.ACTION_UP){
if (((posX >= event.getX() && posX <= event.getX() + 10) || (posX <= event
.getX() && posX >= event.getX() - 10))
&& ((posY >= event.getY() && posY <= event.getY() + 10) || (posY <= event
.getY() && posY >= event.getY() - 10))){
//Do your thing
}
}
return true;
}
});
I think the proper way to do this is by implementing onClickListener instead of onTouchListener.
And yes, the very reason is because the View will be touched when the user only intent to scroll the ListView.
override this method and done with respect to your requirement.
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (isScrooling) {
return super.onInterceptTouchEvent(ev);
} else {
return false;
}
}
I have a ViewPager of images, and I want to make it slide in the following way:
If I click on the right (left) side of the screen, go to previous (next) image. It's like the screen is two halves and each half moves to a direction on click.
How can I implement this?
You can get Disaplay width
Then you can override onTouchEvent in your viewpager.
When you get MotionEvent object - you can get 'tap' coordinates and you will be able to understand on wich side of screen user clicked and handle it.
Set on touch listener for your ViewPager or contentview of ViewPager item.
Take the half of the screen/view width, check if event.getX() is greater than the half value, if so, go to next, otherwise to the previous.
#Override
public boolean onTouch(View v, MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_DOWN){
mDownX = ev.getX();
mDownY = ev.getY();
isOnClick = true;
}else if(ev.getAction() == MotionEvent.ACTION_UP ){
if (isOnClick ) {
if(ev.getX() > mViewPager.getWidth()/2) {
//go to next
}else{
//go to previous
}
return true;
}
}else if(ev.getAction() == MotionEvent.ACTION_MOVE){
if (isOnClick && (Math.abs(mDownX - ev.getX()) > DRAG_THRESHOLD || Math.abs(mDownY - ev.getY()) > DRAG_THRESHOLD)) {
isOnClick = false;
return false;
}
}
return false
}
I have some ImageViews inside a HorizontalScrollView.
I would like to be able to drag and drop the ImageViews somewhere else, but still maintain scrolling capability. Dragging should only be activated when the user starts a mostly vertical motion with their finger.
For now, I have drag and drop activate on long-press, but that is not a good solution.
To illustrate:
I had to do exactly this as well. After reading http://techin-android.blogspot.in/2011/11/swipe-event-in-android-scrollview.html I adapted the code as follows:
class MyOnTouchListener implements View.OnTouchListener {
static final int MIN_DISTANCE_Y = 40;
private float downY, upY;
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
downY = event.getY();
return true;
}
case MotionEvent.ACTION_MOVE: {
upY = event.getY();
float deltaY = downY - upY;
// swipe vertical?
if (Math.abs(deltaY) > MIN_DISTANCE_Y) {
if (deltaY < 0) {
//Start your drag here if appropriate
return true;
}
if (deltaY > 0) {
//Or start your drag here if appropriate
return true;
}
}
}
}
return false;
}
}
And then set the listener on the ImageViews:
imageView.setOnTouchListener(new MyOnTouchListener());
In this version of the code I am only checking for movement in the vertical direction (I also changed the minimum movement to be 40 instead of 100 as in the original code). If a vertical movement is detected, the specific ImageView can begin to drag or do any other actions you want. If a vertical movement is not detected, the ImageView's MyTouchListener returns false which means the ImageView does not consume the touch event. This allows the parent ScrollView to eventually get the touch event and consume it (for scroll detection). The answers here are helpful for understanding touch events: MotionEvent handling in ScrollView in Android.