Fling gesture detection on grid layout

前端 未结 18 1594
遥遥无期
遥遥无期 2020-11-21 04:38

I want to get fling gesture detection working in my Android application.

What I have is a GridLayout that contains 9 ImageView

相关标签:
18条回答
  • 2020-11-21 05:37

    This question is kind of old and in July 2011 Google released the Compatibility Package, revision 3) which includes the ViewPager that works with Android 1.6 upwards. The GestureListener answers posted for this question don't feel very elegant on Android. If you're looking for the code used in switching between photos in the Android Gallery or switching views in the new Play Market app then it's definitely ViewPager.

    Here's some links for more info:

    • http://android-developers.blogspot.com/2011/08/horizontal-view-swiping-with-viewpager.html
    • http://mobile.tutsplus.com/tutorials/android/android-user-interface-design-horizontal-view-paging/
    • http://thepseudocoder.wordpress.com/2011/10/05/android-page-swiping-using-viewpager/
    0 讨论(0)
  • 2020-11-21 05:38

    I nedded a more generic Class , I took Tomas's class and added an Interface that send events to your Activity or Fragment. it will register the listener on the constructor so be sure you implement the interface or an ClassCastException will be thorwn. the interface returns one of the four final int defined in the class and will return the view on which it was activated upon.

    import android.app.Activity;
    import android.support.v4.app.Fragment;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    
    public class SwipeDetector implements View.OnTouchListener{
    
        static final int MIN_DISTANCE = 100;
        private float downX, downY, upX, upY;
        public final static int RIGHT_TO_LEFT=1;
        public final static int LEFT_TO_RIGHT=2;
        public final static int TOP_TO_BOTTOM=3;
        public final static int BOTTOM_TO_TOP=4;
        private View v;
    
        private onSwipeEvent swipeEventListener;
    
    
        public SwipeDetector(Activity activity,View v){
            try{
                swipeEventListener=(onSwipeEvent)activity;
            }
            catch(ClassCastException e)
            {
                Log.e("ClassCastException",activity.toString()+" must implement SwipeDetector.onSwipeEvent");
            } 
            this.v=v;
        }
        public SwipeDetector(Fragment fragment,View v){
            try{
                swipeEventListener=(onSwipeEvent)fragment;
            }
            catch(ClassCastException e)
            {
                Log.e("ClassCastException",fragment.toString()+" must implement SwipeDetector.onSwipeEvent");
            } 
            this.v=v;
        }
    
    
        public void onRightToLeftSwipe(){   
            swipeEventListener.SwipeEventDetected(v,RIGHT_TO_LEFT);
        }
    
        public void onLeftToRightSwipe(){   
            swipeEventListener.SwipeEventDetected(v,LEFT_TO_RIGHT);
        }
    
        public void onTopToBottomSwipe(){   
            swipeEventListener.SwipeEventDetected(v,TOP_TO_BOTTOM);
        }
    
        public void onBottomToTopSwipe(){
            swipeEventListener.SwipeEventDetected(v,BOTTOM_TO_TOP);
        }
    
        public boolean onTouch(View v, MotionEvent event) {
            switch(event.getAction()){
            case MotionEvent.ACTION_DOWN: {
                downX = event.getX();
                downY = event.getY();
                return true;
            }
            case MotionEvent.ACTION_UP: {
                upX = event.getX();
                upY = event.getY();
    
                float deltaX = downX - upX;
                float deltaY = downY - upY;
    
                //HORIZONTAL SCROLL
                if(Math.abs(deltaX) > Math.abs(deltaY))
                {
                    if(Math.abs(deltaX) > MIN_DISTANCE){
                        // left or right
                        if(deltaX < 0) 
                        {
                            this.onLeftToRightSwipe();
                            return true;
                        }
                        if(deltaX > 0) {
                            this.onRightToLeftSwipe();
                            return true; 
                        }
                    }
                    else {
                        //not long enough swipe...
                        return false; 
                    }
                }
                //VERTICAL SCROLL
                else 
                {
                    if(Math.abs(deltaY) > MIN_DISTANCE){
                        // top or down
                        if(deltaY < 0) 
                        { this.onTopToBottomSwipe();
                        return true; 
                        }
                        if(deltaY > 0)
                        { this.onBottomToTopSwipe(); 
                        return true;
                        }
                    }
                    else {
                        //not long enough swipe...
                        return false;
                    }
                }
    
                return true;
            }
            }
            return false;
        }
        public interface onSwipeEvent
        {
            public void SwipeEventDetected(View v , int SwipeType);
        }
    
    }
    
    0 讨论(0)
  • 2020-11-21 05:39

    The swipe gesture detector code above is very useful! You may however wish to make this solution density agnostic by using the following relative values (REL_SWIPE) rather than the absolute values (SWIPE_)

    DisplayMetrics dm = getResources().getDisplayMetrics();
    
    int REL_SWIPE_MIN_DISTANCE = (int)(SWIPE_MIN_DISTANCE * dm.densityDpi / 160.0f);
    int REL_SWIPE_MAX_OFF_PATH = (int)(SWIPE_MAX_OFF_PATH * dm.densityDpi / 160.0f);
    int REL_SWIPE_THRESHOLD_VELOCITY = (int)(SWIPE_THRESHOLD_VELOCITY * dm.densityDpi / 160.0f);
    
    0 讨论(0)
  • 2020-11-21 05:39

    You can use the droidQuery library to handle flings, clicks, long clicks, and custom events. The implementation is built on my previous answer below, but droidQuery provides a slick, simple syntax:

    //global variables    private boolean isSwiping = false;
    private SwipeDetector.Direction swipeDirection = null;
    private View v;//must be instantiated before next call.
    
    //swipe-handling code
    $.with(v).swipe(new Function() {
        @Override
        public void invoke($ droidQuery, Object... params) {
            if (params[0] == SwipeDetector.Direction.START)
                isSwiping = true;
            else if (params[0] == SwipeDetector.Direction.STOP) {
                if (isSwiping) {                    isSwiping = false;
                    if (swipeDirection != null) {
                        switch(swipeDirection) {
                            case DOWN :                                //TODO: Down swipe complete, so do something
                                break;
                            case UP :
                                //TODO: Up swipe complete, so do something
                                break;
                            case LEFT :
                                //TODO: Left swipe complete, so do something
                                break;
                            case RIGHT :
                                //TODO: Right swipe complete, so do something
                                break;
                            default :                                break;
                        }
                    }                }
            }
            else {
                swipeDirection = (SwipeDetector.Direction) params[0];
            }
        }
    });
    

    Original Answer

    This answer uses a combination of components from the other answers here. It consists of the SwipeDetector class, which has an inner interface for listening for events. I also provide a RelativeLayout to show how to override a View's onTouch method to allow both swipe events and other detected events (such as clicks or long clicks).

    SwipeDetector

    package self.philbrown;
    
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewConfiguration;
    
    /**
     * Detect Swipes on a per-view basis. Based on original code by Thomas Fankhauser on StackOverflow.com,
     * with adaptations by other authors (see link).
     * @author Phil Brown
     * @see <a href="http://stackoverflow.com/questions/937313/android-basic-gesture-detection">android-basic-gesture-detection</a>
     */
    public class SwipeDetector implements View.OnTouchListener
    {
        /**
         * The minimum distance a finger must travel in order to register a swipe event.
         */
        private int minSwipeDistance;
    
        /** Maintains a reference to the first detected down touch event. */
        private float downX, downY;
    
        /** Maintains a reference to the first detected up touch event. */
        private float upX, upY;
    
        /** provides access to size and dimension contants */
        private ViewConfiguration config;
    
        /**
         * provides callbacks to a listener class for various swipe gestures.
         */
        private SwipeListener listener;
    
        public SwipeDetector(SwipeListener listener)
        {
            this.listener = listener;
        }
    
    
        /**
         * {@inheritDoc}
         */
        public boolean onTouch(View v, MotionEvent event)
        {
            if (config == null)
            {
                    config = ViewConfiguration.get(v.getContext());
                    minSwipeDistance = config.getScaledTouchSlop();
            }
    
            switch(event.getAction())
            {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                downY = event.getY();
                return true;
            case MotionEvent.ACTION_UP:
                upX = event.getX();
                upY = event.getY();
    
                float deltaX = downX - upX;
                float deltaY = downY - upY;
    
                // swipe horizontal?
                if(Math.abs(deltaX) > minSwipeDistance)
                {
                    // left or right
                    if (deltaX < 0)
                    {
                            if (listener != null)
                            {
                                    listener.onRightSwipe(v);
                                    return true;
                            }
                    }
                    if (deltaX > 0)
                    {
                            if (listener != null)
                            {
                                    listener.onLeftSwipe(v);
                                    return true;
                            }
                    }
                }
    
                // swipe vertical?
                if(Math.abs(deltaY) > minSwipeDistance)
                {
                    // top or down
                    if (deltaY < 0)
                    {
                            if (listener != null)
                            {
                                    listener.onDownSwipe(v);
                                    return true;
                            }
                    }
                    if (deltaY > 0)
                    {
                            if (listener != null)
                            {
                                    listener.onUpSwipe(v);
                                    return true;
                            }
                    }
                }
            }
            return false;
        }
    
        /**
         * Provides callbacks to a registered listener for swipe events in {@link SwipeDetector}
         * @author Phil Brown
         */
        public interface SwipeListener
        {
            /** Callback for registering a new swipe motion from the bottom of the view toward its top. */
            public void onUpSwipe(View v);
            /** Callback for registering a new swipe motion from the left of the view toward its right. */
            public void onRightSwipe(View v);
            /** Callback for registering a new swipe motion from the right of the view toward its left. */
            public void onLeftSwipe(View v);
            /** Callback for registering a new swipe motion from the top of the view toward its bottom. */
            public void onDownSwipe(View v);
        }
    }
    

    Swipe Interceptor View

    package self.philbrown;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.widget.RelativeLayout;
    
    import com.npeinc.module_NPECore.model.SwipeDetector;
    import com.npeinc.module_NPECore.model.SwipeDetector.SwipeListener;
    
    /**
     * View subclass used for handling all touches (swipes and others)
     * @author Phil Brown
     */
    public class SwipeInterceptorView extends RelativeLayout
    {
        private SwipeDetector swiper = null;
    
        public void setSwipeListener(SwipeListener listener)
        {
            if (swiper == null)
                swiper = new SwipeDetector(listener);
        }
    
        public SwipeInterceptorView(Context context) {
            super(context);
        }
    
        public SwipeInterceptorView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public SwipeInterceptorView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent e)
        {
            boolean swipe = false, touch = false;
            if (swiper != null)
                swipe = swiper.onTouch(this, e);
            touch = super.onTouchEvent(e);
            return swipe || touch;
        }
    }
    
    0 讨论(0)
  • 2020-11-21 05:39

    Gestures are those subtle motions to trigger interactions between the touch screen and the user. It lasts for the time between the first touch on the screen to the point when the last finger leaves the surface.

    Android provides us with a class called GestureDetector using which we can detect common gestures like tapping down and up, swiping vertically and horizontally (fling), long and short press, double taps, etc. and attach listeners to them.

    Make our Activity class implement GestureDetector.OnDoubleTapListener (for double tap gesture detection) and GestureDetector.OnGestureListener interfaces and implement all the abstract methods.For more info. you may visit https://developer.android.com/training/gestures/detector.html . Courtesy

    For Demo Test.GestureDetectorDemo

    0 讨论(0)
  • 2020-11-21 05:41

    There is a lot of excellent information here. Unfortunately a lot of this fling-processing code is scattered around on various sites in various states of completion, even though one would think this is essential to many applications.

    I've taken the time to create a fling listener that verifies that the appropriate conditions are met. I've added a page fling listener that adds more checks to ensure that flings meet the threshold for page flings. Both of these listeners allow you to easily restrict flings to the horizontal or vertical axis. You can see how it's used in a view for sliding images. I acknowledge that the people here have done most of the research---I've just put it together into a usable library.

    These last few days represent my first stab at coding on Android; expect much more to come.

    0 讨论(0)
提交回复
热议问题