Fling gesture detection on grid layout

前端 未结 18 1553
遥遥无期
遥遥无期 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:24

    If you dont like to create a separate class or make code complex,
    You can just create a GestureDetector variable inside OnTouchListener and make your code more easier

    namVyuVar can be any name of the View on which you need to set the listner

    namVyuVar.setOnTouchListener(new View.OnTouchListener()
    {
        @Override
        public boolean onTouch(View view, MotionEvent MsnEvtPsgVal)
        {
            flingActionVar.onTouchEvent(MsnEvtPsgVal);
            return true;
        }
    
        GestureDetector flingActionVar = new GestureDetector(getApplicationContext(), new GestureDetector.SimpleOnGestureListener()
        {
            private static final int flingActionMinDstVac = 120;
            private static final int flingActionMinSpdVac = 200;
    
            @Override
            public boolean onFling(MotionEvent fstMsnEvtPsgVal, MotionEvent lstMsnEvtPsgVal, float flingActionXcoSpdPsgVal, float flingActionYcoSpdPsgVal)
            {
                if(fstMsnEvtPsgVal.getX() - lstMsnEvtPsgVal.getX() > flingActionMinDstVac && Math.abs(flingActionXcoSpdPsgVal) > flingActionMinSpdVac)
                {
                    // TskTdo :=> On Right to Left fling
    
                    return false;
                }
                else if (lstMsnEvtPsgVal.getX() - fstMsnEvtPsgVal.getX() > flingActionMinDstVac && Math.abs(flingActionXcoSpdPsgVal) > flingActionMinSpdVac)
                {
                    // TskTdo :=> On Left to Right fling
    
                    return false;
                }
    
                if(fstMsnEvtPsgVal.getY() - lstMsnEvtPsgVal.getY() > flingActionMinDstVac && Math.abs(flingActionYcoSpdPsgVal) > flingActionMinSpdVac)
                {
                    // TskTdo :=> On Bottom to Top fling
    
                    return false;
                }
                else if (lstMsnEvtPsgVal.getY() - fstMsnEvtPsgVal.getY() > flingActionMinDstVac && Math.abs(flingActionYcoSpdPsgVal) > flingActionMinSpdVac)
                {
                    // TskTdo :=> On Top to Bottom fling
    
                    return false;
                }
                return false;
            }
        });
    });
    
    0 讨论(0)
  • 2020-11-21 05:25

    To all: don't forget about case MotionEvent.ACTION_CANCEL:

    it calls in 30% swipes without ACTION_UP

    and its equal to ACTION_UP in this case

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

    My version of solution proposed by Thomas Fankhauser and Marek Sebera (does not handle vertical swipes):

    SwipeInterface.java

    import android.view.View;
    
    public interface SwipeInterface {
    
        public void onLeftToRight(View v);
    
        public void onRightToLeft(View v);
    }
    

    ActivitySwipeDetector.java

    import android.content.Context;
    import android.util.DisplayMetrics;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewConfiguration;
    
    public class ActivitySwipeDetector implements View.OnTouchListener {
    
        static final String logTag = "ActivitySwipeDetector";
        private SwipeInterface activity;
        private float downX, downY;
        private long timeDown;
        private final float MIN_DISTANCE;
        private final int VELOCITY;
        private final float MAX_OFF_PATH;
    
        public ActivitySwipeDetector(Context context, SwipeInterface activity){
            this.activity = activity;
            final ViewConfiguration vc = ViewConfiguration.get(context);
            DisplayMetrics dm = context.getResources().getDisplayMetrics();
            MIN_DISTANCE = vc.getScaledPagingTouchSlop() * dm.density;
            VELOCITY = vc.getScaledMinimumFlingVelocity();
            MAX_OFF_PATH = MIN_DISTANCE * 2;            
        }
    
        public void onRightToLeftSwipe(View v){
            Log.i(logTag, "RightToLeftSwipe!");
            activity.onRightToLeft(v);
        }
    
        public void onLeftToRightSwipe(View v){
            Log.i(logTag, "LeftToRightSwipe!");
            activity.onLeftToRight(v);
        }
    
        public boolean onTouch(View v, MotionEvent event) {
            switch(event.getAction()){
            case MotionEvent.ACTION_DOWN: {
                Log.d("onTouch", "ACTION_DOWN");
                timeDown = System.currentTimeMillis();
                downX = event.getX();
                downY = event.getY();
                return true;
            }
            case MotionEvent.ACTION_UP: {
                Log.d("onTouch", "ACTION_UP");
                long timeUp = System.currentTimeMillis();
                float upX = event.getX();
                float upY = event.getY();
    
                float deltaX = downX - upX;
                float absDeltaX = Math.abs(deltaX); 
                float deltaY = downY - upY;
                float absDeltaY = Math.abs(deltaY);
    
                long time = timeUp - timeDown;
    
                if (absDeltaY > MAX_OFF_PATH) {
                    Log.i(logTag, String.format("absDeltaY=%.2f, MAX_OFF_PATH=%.2f", absDeltaY, MAX_OFF_PATH));
                    return v.performClick();
                }
    
                final long M_SEC = 1000;
                if (absDeltaX > MIN_DISTANCE && absDeltaX > time * VELOCITY / M_SEC) {
                    if(deltaX < 0) { this.onLeftToRightSwipe(v); return true; }
                    if(deltaX > 0) { this.onRightToLeftSwipe(v); return true; }
                } else {
                    Log.i(logTag, String.format("absDeltaX=%.2f, MIN_DISTANCE=%.2f, absDeltaX > MIN_DISTANCE=%b", absDeltaX, MIN_DISTANCE, (absDeltaX > MIN_DISTANCE)));
                    Log.i(logTag, String.format("absDeltaX=%.2f, time=%d, VELOCITY=%d, time*VELOCITY/M_SEC=%d, absDeltaX > time * VELOCITY / M_SEC=%b", absDeltaX, time, VELOCITY, time * VELOCITY / M_SEC, (absDeltaX > time * VELOCITY / M_SEC)));
                }
    
            }
            }
            return false;
        }
    
    }
    
    0 讨论(0)
  • 2020-11-21 05:28

    Also as a minor enhancement.

    The main reason for the try/catch block is that e1 could be null for the initial movement. in addition to the try/catch, include a test for null and return. similar to the following

    if (e1 == null || e2 == null) return false;
    try {
    ...
    } catch (Exception e) {}
    return false;
    
    0 讨论(0)
  • 2020-11-21 05:29

    There's a built-in interface that you can use directly for all gestures:
    Here is an explanation for a basic level user: enter image description here There is 2 imports be careful in choosing that both are diferent enter image description here enter image description here

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

    One of the answers above mentions handling different pixel density but suggests computing the swipe parameters by hand. It is worth noting that you can actually obtain scaled, reasonable values from the system using ViewConfiguration class:

    final ViewConfiguration vc = ViewConfiguration.get(getContext());
    final int swipeMinDistance = vc.getScaledPagingTouchSlop();
    final int swipeThresholdVelocity = vc.getScaledMinimumFlingVelocity();
    final int swipeMaxOffPath = vc.getScaledTouchSlop();
    // (there is also vc.getScaledMaximumFlingVelocity() one could check against)
    

    I noticed that using these values causes the "feel" of fling to be more consistent between the application and rest of system.

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