so I tried Zala's code for handling the gestures from this question android how to handle right to left swipe gestures, it works but the problem is my component is inside a scrollview so the gestures sometimes are detected sometimes not, I tried few different codes to solve this scrollview issue still the same behavior.
Anyone could help please !
scrollView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:{
downX = event.getX();}
case MotionEvent.ACTION_UP:{
upX = event.getX();
float deltaX = downX - upX;
if(Math.abs(deltaX)>0){
if(deltaX>=0){
swipeToRight();
return true;
}else{
swipeToLeft();
return true;
}
}
}
}
return false;
}
});
Related
The swipe of ViewPager is smooth inside the vertical scrollview when I add this code into my ViewPager.
mPager.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
v.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
But when I add onClickListener to my ImageView [which is found in the Fragment added to the Adapter of the Viewpager], the swipe of my ViewPager is incorrect. Incorrect wherein I need to have a STRAIGHT HORIZONTAL LINE swipe for it to go to another page unlike before [when I did not add the onClickListener], the viewpager goes to the next page even I do DIAGONAL swiping. Any help is much appreciated. Thanks.
I just used setontouchlistener to my imageview and set conditions there.
Here's the code:
imgCarousel.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
pStart = new Point((int) event.getX(), (int) event.getY());
break;
}
case MotionEvent.ACTION_UP: {
break;
}
case MotionEvent.ACTION_MOVE:{
break;
}
case MotionEvent.ACTION_CANCEL:{
Point pCancel = new Point((int) event.getX(), (int) event.getY());
int difference = pStart.x - pCancel.x;
if(difference > 10){
mPager.setCurrentItem(HomeCarousel.currentPage+1);
}
}
default:
break;
}
return true;
}
});
I think, it happens because ImageView intercept touchEvent using onClickListener.
You can use GestureOverlayView with your ImageView - http://developer.android.com/reference/android/gesture/GestureOverlayView.html
It could handle touch events without intercepting them.
I've got a ViewFlipper at the side of the screen in my app containing a bunch of different views, and I would like the user to be able to dismiss this by swiping to the left. So I did the usual...
private class SwipeDetector extends SimpleOnGestureListener {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//Dismiss view
}
#Override
public boolean onDown(MotionEvent e) {
return true;
}
}
...and then set the onTouchListener of the ViewFlipper to call onTouchEvent in SwipeDetector. It all worked great, however I then noticed because it was consuming all the touch events going into the ViewFlipper, I couldn't click anything when the ViewFlipper itself. If I don't override onDown or I make it return false then the TouchListener ignores the rest of the event and I don't get the fling. I'm happy to hack together some kind of custom swipe detection if I could even handle all the ACTION_MOVE events following the user touching the ViewFlipper but can't even do that. Is there any way to keep listening to the MotionEvent without consuming the onDown?
What works for me is extending View.OnTouchListener instead of SimpleGestureListener, and override onTouch method. Please, take this snippet as a very simple (and improvable) approach to get horizontal swipe detection.-
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
downX = event.getX();
return true;
}
case MotionEvent.ACTION_UP: {
upX = event.getX();
float deltaX = downX - upX;
if (Math.abs(deltaX) > MIN_DISTANCE) {
if (deltaX < 0) {
this.onLeftToRightSwipe();
return true;
}
if (deltaX > 0) {
this.onRightToLeftSwipe();
return true;
}
return true;
}
return true;
}
}
return false;
}
Did you notice the GestureDetector? It is available since API Version 1.
http://developer.android.com/reference/android/view/GestureDetector.OnGestureListener.html
Both fling and scroll gestures are handled.
I would like to set up following layout with working scroll and click events:
My CustomSlidingDrawer.xml:
<com.project.util.CustomSliderDrawer
android:id="#+id/slidingDrawerHotelList"
android:layout_width="0dp"
android:layout_height="match_parent"
android:allowSingleTap="false"
android:content="#+id/content"
android:handle="#+id/handle"
android:orientation="horizontal" >
<RelativeLayout
android:id="#+id/handle"
android:layout_width="0dp"
android:layout_height="match_parent" >
<RelativeLayout
android:id="#+id/content"
android:layout_width="0dp"
android:layout_height="0dp" >
</RelativeLayout>
</RelativeLayout>
</com.project.util.CustomSliderDrawer>
The width of the elements are set during runtime.
Here I have to mention, that my real content is in the handle of the Drawer, and the content is only a dummy. I'm doing that in this way, because I was not able to hide the handle. Or make it invisible. So, if I want to swipe in I touch the handle (my content) and pull. In the SlidingDrawer, the handle is a placeholder for a fragment which contains a CustomListView.
What now works: I can scroll the SlidingDrawer.
What behavior I would like to gain:
On the SlidingDrawer the MotionEvents are detected in X-Axis direction (Vertical swipe). If a MotionEvent in Y-Axis direction is detected, then the Events shoud go to my CustomListView. Even the onClicks should pass through to the ListView.
What I've tried: I read a lot: here, this page and this one
Then I tried to put all the navigation control in the main activity, what makes really sense in my eyes:
MainActivity:
slidingDrawer.setOnTouchListener(new OnTouchListener() {
int downX, downY;
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
downX = (int) event.getX();
downY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
int deltaX = downX - (int) event.getX();
int deltaY = downY - (int) event.getY();
if (Math.abs(deltaX) > Math.abs(deltaY)) {
Log.i(TAG, "scrollX direction");
isVerticalSwipe = true;
} else {
Log.i(TAG, "scrollY direction");
isVerticalSwipe = false;
}
break;
case MotionEvent.ACTION_UP:
break;
}
return false;
}
});
But when I try here to return "isVerticalSwipe" as local, the SlidingDrawer works not properly anymore. :-(
The 2nd try was to intercept the touch events in the custom sliding drawer:
CustomSlidingDrawer:
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG, "onInterceptTouchEvent ACTION_DOWN");
xDistance = yDistance = 0f;
downX = (int) ev.getX();
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "onInterceptTouchEvent ACTION_MOVE");
final int curX = (int) ev.getX();
final int curY = (int) ev.getY();
xDistance += Math.abs(curX - downX);
yDistance += Math.abs(curY - downY);
downX = curX;
downY = curY;
if (xDistance > yDistance)
return false;
}
return super.onInterceptTouchEvent(ev);
}
Here happens only the DOWN event and the MOVE event is never reached.
I also made some trys with "dispatchTouchEvent" but I got no success.
I know, that the events will pass through the "layer" of my views - from top to bottom.
So it would be perfect to know, how I can implement the construct from the first link above in my CustomSlidingDrawer (= top view) and when a vertical swipe is detected keep and handle it and if it's a horizontal swipe, then please send it to the CustomListView and perform there the events.
Any help, thoughts, ideas or code snippets are appreciated. :)
Thank you!
[EDIT]
I've made some progress. I get now my events from the SlidingDrawer down to my ListView. I can scroll and click in the list - that works fine. But unfortunately, my SlidingDrawer shows no reaction anymore. These lines are in my custom SlidingDrawer:
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
gestureDetector = new GestureDetector(new MyGestureDetector());
if (gestureDetector.onTouchEvent(event)) {
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP
|| event.getAction() == MotionEvent.ACTION_CANCEL) {
return false;
} else {
Log.i(TAG, "gestureDetector returned false");
return false;
}
}
class MyGestureDetector extends SimpleOnGestureListener {
#Override
public boolean onDown(MotionEvent e) {
Log.i(TAG, "onDown");
downX = (int) e.getX();
downY = (int) e.getY();
return false;
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
float deltaX = downX - e2.getX();
float deltaY = downY - e2.getY();
if (Math.abs(deltaX) > Math.abs(deltaY)) {
Log.i(TAG, "scrollX direction");
return true;
} else {
Log.i(TAG, "scrollY direction");
return false;
}
}
}
I don't really understand why it's not working, if there is a swipe in x-direction, then my Drawer should handle the gesture, bc I return true. Instead every event is forwarded to the ListView.
I tried to run "dispatchTouchEvent" before the "onInterceptTouchEvent" but I had no success. Maybe there is a better solution instead of using a SlidingDrawer for moving views by finger?
Okay, after a lot of tears, sweat and blood I finally found a solution which works for me: I don't take a SlidingDrawer anymore and move my layout via changing the LayoutParams.
Over the "dispatchTouchEvent" I get access to my list.
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (mGestureDetector.onTouchEvent(ev)) {
return true;
}
if (ev.getAction() == MotionEvent.ACTION_UP) {
Log.i(TAG, "ACTION_UP");
Log.i(TAG, "getLeft: " + getLeft());
if (getLeft() < 280) {
// run ani to left
} else {
// run ani to right
}
}
return super.dispatchTouchEvent(ev);
}
And in my GestureDetector I handle in the overridden onScroll-function the layout translation. If someone has need for the detector don't hesitate to ask, I'll share.
I have a ViewPager which uses GridViews for pages. I would like the ViewPager to switch pages when I swipe across the screen.
The problem is that swipes are not detected when they are made across the GridView. Outside of the GridView, the swipes work correctly; it seems that the GridView is trapping all touch events without passing it to ViewPager first.
While fiddling with the source code, I did this to a custom class extended from GridView:
#Override
public boolean onTouchEvent(MotionEvent event) {
return pager.onInterceptTouchEvent(event);
}
-- where pager refers to the ViewPager class. With this, ViewPager will correctly detect swipes and move pages accordingly, but it doesn't allow GridView to accept any events, so I can't click on the items.
What I would like to be able to do is correctly detect swipes in ViewPager and item clicks on GridView.
I had trouble with colig's implementation, but I was able to get it to work by subclassing ViewPager and overriding the onInterceptTouchEvent() method. I only checked for swipes in the X direction to allow for vertical scrolling if necessary.
private static final int minSwipeDistance = 30;
private float mTouchX;
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean response = super.onInterceptTouchEvent(event);
float x = event.getX();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mTouchX = x;
break;
case MotionEvent.ACTION_MOVE:
float dX = Math.abs(x - mTouchX);
if (dX > minSwipeDistance)
return true;
break;
}
return response;
}
Alix is on the right track. I managed to come up with this simple-looking fix. I'm not entirely sure of how it works, but it does! And for future reference, it works for other kinds of views too -- TableLayout, for example -- not just GridView.
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
x = event.getX();
y = event.getY();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
downX = x;
downY = y;
return super.onInterceptTouchEvent(event);
}
case MotionEvent.ACTION_MOVE: {
deltaX = Math.abs(downX - x);
deltaY = Math.abs(downY - y);
return super.onTouchEvent(event);
}
case MotionEvent.ACTION_UP: {
if (deltaX > 4 && deltaY > 4) {
super.onTouchEvent(event);
}
}
}
return super.onInterceptTouchEvent(event);
}
You can override onInterceptTouchEvent for dispatch evenement where you want
How to handle touchscreen events for OpenGl programs in Android? I have checked out several posts related to this question, like-
How to intercept touchscreen events in Android OpenGL ES?
But my problem is that I am only able to handle MotionEvent.ACTION_DOWN events, even if I write the handler for other type of events, those handlers are not called.Android docs sample also uses this event only.Are the other events supported??
My onTouch handler looks something like this-
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN :
Log.d(TAG, "mode=DOWN");
break;
case MotionEvent.ACTION_UP :
case MotionEvent.ACTION_POINTER_UP :
Log.d(TAG, "mode=UP");
break;
}
return true;
}
Try doing a series of if/else statements and see if they work, then try converting it to a switch statement. Maybe take out break and instead return true.
This is how I do it:
#Override
public boolean onTouch(View v, MotionEvent event) {
final float mouseSensitivity = 0.5f;
if(event.getAction()==MotionEvent.ACTION_DOWN){
startX = event.getX();
startY = event.getY();
} else if(event.getAction()==MotionEvent.ACTION_UP){
startX = 0.0f;
startY = 0.0f;
} else if(event.getAction()==MotionEvent.ACTION_MOVE){
graphicsRenderer.rotate((startY - event.getY()) * mouseSensitivity,(startX - event.getX()) * mouseSensitivity);
startX = event.getX();
startY = event.getY();
}
return true;
}
// Where startX and startY are global int variables;