Android:如何处理从右到左的滑动手势

Posted

技术标签:

【中文标题】Android:如何处理从右到左的滑动手势【英文标题】:Android: How to handle right to left swipe gestures 【发布时间】:2011-05-07 13:26:17 【问题描述】:

我希望我的应用能够识别用户何时在手机屏幕上从右向左滑动。

如何做到这一点?

【问题讨论】:

查看此链接***.com/questions/937313/… 查看我关于如何上/下/左/右滑动手势的回答***.com/questions/13095494/… 检查我的图书馆,这可能会有所帮助github.com/Udioshi85/libSwipes 在这里检查 Kotlin 中接受的答案:***.com/a/53791260/2201814 【参考方案1】:

OnSwipeTouchListener.java

import android.content.Context;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class OnSwipeTouchListener implements OnTouchListener 

    private final GestureDetector gestureDetector;

    public OnSwipeTouchListener (Context ctx)
        gestureDetector = new GestureDetector(ctx, new GestureListener());
    

    @Override
    public boolean onTouch(View v, MotionEvent event) 
        return gestureDetector.onTouchEvent(event);
    

    private final class GestureListener extends SimpleOnGestureListener 

        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) 
            return true;
        

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) 
            boolean result = false;
            try 
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) 
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) 
                        if (diffX > 0) 
                            onSwipeRight();
                         else 
                            onSwipeLeft();
                        
                        result = true;
                    
                
                else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) 
                    if (diffY > 0) 
                        onSwipeBottom();
                     else 
                        onSwipeTop();
                    
                    result = true;
                
             catch (Exception exception) 
                exception.printStackTrace();
            
            return result;
        
    

    public void onSwipeRight() 
    

    public void onSwipeLeft() 
    

    public void onSwipeTop() 
    

    public void onSwipeBottom() 
    

用法:

imageView.setOnTouchListener(new OnSwipeTouchListener(MyActivity.this) 
    public void onSwipeTop() 
        Toast.makeText(MyActivity.this, "top", Toast.LENGTH_SHORT).show();
    
    public void onSwipeRight() 
        Toast.makeText(MyActivity.this, "right", Toast.LENGTH_SHORT).show();
    
    public void onSwipeLeft() 
        Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show();
    
    public void onSwipeBottom() 
        Toast.makeText(MyActivity.this, "bottom", Toast.LENGTH_SHORT).show();
    

);

【讨论】:

效果很好,但是 super.onTouch(view, motionEvent);在 Eclipse 中给我错误警告“类型对象未定义”。删除这个效果很好。 Thanks 就像一个魅力,但你应该添加一个构造函数到 OnSwipeTouchListener 接收上下文,因为 GestureDetector 的构造函数自 API 级别 3 以来已被弃用,并在该构造函数中实例化 GestureDetector . 感谢这些修改对我有用:***.com/a/19506010/401403 但永远不会调用“onDown”。结果,我的 e1 始终为空,我对此无能为力。 我对这个答案的解决方法是将onTouch移动到OnSwipeTouchListener定义中,否则我的IDE会弹出“访问私有成员”错误【参考方案2】:

此代码检测左右滑动,避免不推荐使用的 API 调用,并且对早期答案进行了其他杂项改进。

/**
 * Detects left and right swipes across a view.
 */
public class OnSwipeTouchListener implements OnTouchListener 

    private final GestureDetector gestureDetector;

    public OnSwipeTouchListener(Context context) 
        gestureDetector = new GestureDetector(context, new GestureListener());
    

    public void onSwipeLeft() 
    

    public void onSwipeRight() 
    

    public boolean onTouch(View v, MotionEvent event) 
        return gestureDetector.onTouchEvent(event);
    

    private final class GestureListener extends SimpleOnGestureListener 

        private static final int SWIPE_DISTANCE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) 
            return true;
        

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) 
            float distanceX = e2.getX() - e1.getX();
            float distanceY = e2.getY() - e1.getY();
            if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) 
                if (distanceX > 0)
                    onSwipeRight();
                else
                    onSwipeLeft();
                return true;
            
            return false;
        
    

像这样使用它:

view.setOnTouchListener(new OnSwipeTouchListener(context) 
    @Override
    public void onSwipeLeft() 
        // Whatever
    
);

【讨论】:

@Jona 你肯定想要一本关于 Android 基础知识的好书或其他资源;否则,试图从 *** 拼凑解决方案将被证明是令人沮丧的。一个不错的选择是官方Training for Android developers。 Starting an Activity 部分讲述了您将放置setOnTouchListener 的位置(通常在onCreate 中)。 contextthis 指针(除非您正在创建片段)。 @Lara,我没试过,但你可以尝试覆盖 SimpleOnGestureListener.onSingleTapConfirmed。 谢谢,爱德华。我还发现将 onDown 的返回值从 true 更改为 false 可以解决问题。 @Signo,包含视图的活动提供上下文。在将视图添加到片段的常见情况下,使用Fragment.getActivity() @coderVishal 根据您的目的,您可能会发现有用的SwipeRefreshLayout、SwipeRefreshLayoutBasic 示例或其变体之一。【参考方案3】:

如果还需要处理点击事件,这里做一些修改:

public class OnSwipeTouchListener implements OnTouchListener 

    private final GestureDetector gestureDetector = new GestureDetector(new GestureListener());

    public boolean onTouch(final View v, final MotionEvent event) 
        return gestureDetector.onTouchEvent(event);
    

    private final class GestureListener extends SimpleOnGestureListener 

        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;


        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) 
            boolean result = false;
            try 
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) 
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) 
                        if (diffX > 0) 
                            result = onSwipeRight();
                         else 
                            result = onSwipeLeft();
                        
                    
                 else 
                    if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) 
                        if (diffY > 0) 
                            result = onSwipeBottom();
                         else 
                            result = onSwipeTop();
                        
                    
                
             catch (Exception exception) 
                exception.printStackTrace();
            
            return result;
        
    

    public boolean onSwipeRight() 
        return false;
    

    public boolean onSwipeLeft() 
        return false;
    

    public boolean onSwipeTop() 
        return false;
    

    public boolean onSwipeBottom() 
        return false;
    

及示例用法:

    background.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View arg0) 
            toggleSomething();
        
    );
    background.setOnTouchListener(new OnSwipeTouchListener() 
        public boolean onSwipeTop() 
            Toast.makeText(MainActivity.this, "top", Toast.LENGTH_SHORT).show();
            return true;
        
        public boolean onSwipeRight() 
            Toast.makeText(MainActivity.this, "right", Toast.LENGTH_SHORT).show();
            return true;
        
        public boolean onSwipeLeft() 
            Toast.makeText(MainActivity.this, "left", Toast.LENGTH_SHORT).show();
            return true;
        
        public boolean onSwipeBottom() 
            Toast.makeText(MainActivity.this, "bottom", Toast.LENGTH_SHORT).show();
            return true;
        
    );

【讨论】:

我看不到您修改后的 OnSwipeTouchListener 中的修改。它到底在哪里? 这应该是公认的答案...差异很微妙但非常重要。首先,没有 onDown()。其次,处理程序返回一个布尔值来表示他们是否消费了事件。如果您需要多个处理程序来处理同一视图(无论如何这应该是默认情况),这一点至关重要。 那个toggleSomething()方法是什么? @tung 只是普通的点击(不是手势)处理程序 @NicolasZozol java 代码风格,所有滑动方向,点击处理程序【参考方案4】:

扩展 Mirek 的答案,适用于您想在滚动视图中使用滑动手势的情况。默认情况下,滚动视图的触摸侦听器被禁用,因此不会发生滚动操作。为了解决这个问题,您需要覆盖 ActivitydispatchTouchEvent 方法,并在您完成自己的侦听器后返回此方法的继承版本。

为了对 Mirek 的代码做一些修改: 我在OnSwipeTouchListener 中为gestureDetector 添加了一个getter。

public GestureDetector getGestureDetector()
    return  gestureDetector;

将 Activity 中的 OnSwipeTouchListener 声明为类范围的字段。

OnSwipeTouchListener onSwipeTouchListener;

相应修改使用代码:

onSwipeTouchListener = new OnSwipeTouchListener(MyActivity.this) 
    public void onSwipeTop() 
        Toast.makeText(MyActivity.this, "top", Toast.LENGTH_SHORT).show();
    
    public void onSwipeRight() 
        Toast.makeText(MyActivity.this, "right", Toast.LENGTH_SHORT).show();
    
    public void onSwipeLeft() 
        Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show();
    
    public void onSwipeBottom() 
        Toast.makeText(MyActivity.this, "bottom", Toast.LENGTH_SHORT).show();
    
);

imageView.setOnTouchListener(onSwipeTouchListener);

并覆盖Activity内部的dispatchTouchEvent方法:

@Override
    public boolean dispatchTouchEvent(MotionEvent ev)
        swipeListener.getGestureDetector().onTouchEvent(ev); 
            return super.dispatchTouchEvent(ev);   
    

现在滚动和滑动操作都应该起作用了。

【讨论】:

这里有个巨大的减号——如果我在滚动视图的任何地方做一个手势,就会调用 touchListener,即使它没有应用于滚动视图本身,而是应用于其中的随机按钮【参考方案5】:

要在单个View 上拥有Click ListenerDoubleClick ListenerOnLongPress ListenerSwipe LeftSwipe RightSwipe UpSwipe Down,您需要setOnTouchListener。即,

view.setOnTouchListener(new OnSwipeTouchListener(MainActivity.this) 

            @Override
            public void onClick() 
                super.onClick();
                // your on click here
            

            @Override
            public void onDoubleClick() 
                super.onDoubleClick();
                // your on onDoubleClick here
            

            @Override
            public void onLongClick() 
                super.onLongClick();
                // your on onLongClick here
            

            @Override
            public void onSwipeUp() 
                super.onSwipeUp();
                // your swipe up here
            

            @Override
            public void onSwipeDown() 
                super.onSwipeDown();
                // your swipe down here.
            

            @Override
            public void onSwipeLeft() 
                super.onSwipeLeft();
                // your swipe left here.
            

            @Override
            public void onSwipeRight() 
                super.onSwipeRight();
                // your swipe right here.
            
        );


为此,您需要实现OnTouchListenerOnSwipeTouchListener 类。

public class OnSwipeTouchListener implements View.OnTouchListener 

private GestureDetector gestureDetector;

public OnSwipeTouchListener(Context c) 
    gestureDetector = new GestureDetector(c, new GestureListener());


public boolean onTouch(final View view, final MotionEvent motionEvent) 
    return gestureDetector.onTouchEvent(motionEvent);


private final class GestureListener extends GestureDetector.SimpleOnGestureListener 

    private static final int SWIPE_THRESHOLD = 100;
    private static final int SWIPE_VELOCITY_THRESHOLD = 100;

    @Override
    public boolean onDown(MotionEvent e) 
        return true;
    

    @Override
    public boolean onSingleTapUp(MotionEvent e) 
        onClick();
        return super.onSingleTapUp(e);
    

    @Override
    public boolean onDoubleTap(MotionEvent e) 
        onDoubleClick();
        return super.onDoubleTap(e);
    

    @Override
    public void onLongPress(MotionEvent e) 
        onLongClick();
        super.onLongPress(e);
    

    // Determines the fling velocity and then fires the appropriate swipe event accordingly
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) 
        boolean result = false;
        try 
            float diffY = e2.getY() - e1.getY();
            float diffX = e2.getX() - e1.getX();
            if (Math.abs(diffX) > Math.abs(diffY)) 
                if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) 
                    if (diffX > 0) 
                        onSwipeRight();
                     else 
                        onSwipeLeft();
                    
                
             else 
                if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) 
                    if (diffY > 0) 
                        onSwipeDown();
                     else 
                        onSwipeUp();
                    
                
            
         catch (Exception exception) 
            exception.printStackTrace();
        
        return result;
    


public void onSwipeRight() 


public void onSwipeLeft() 


public void onSwipeUp() 


public void onSwipeDown() 


public void onClick() 



public void onDoubleClick() 



public void onLongClick() 



【讨论】:

Zala 的解决方案简单明了,对我在 android 中的滑动操作帮助很大。此解决方案将解决在滑动手势方面遇到问题的初学者。 @Jaydipsinh Zala,你节省了我的时间,太棒了。这将解决我在滚动时滚动顶部和底部指示器的问题。 这就是我所说的完整答案。当我添加滑动时,我丢失了点击属性,因此我需要覆盖 onClick 方法,如本答案所示。谢谢大佬! @Jaydipsinh Zala 不确定我做错了什么,当我将 OnSwipeTouchListener 添加到我的 webView 时,它会删除与 webview 内部网站的交互。你能帮忙吗?【参考方案6】:

@Mirek Rusin 的 Kotlin 版本在这里:

OnSwipeTouchListener.kt:

open class OnSwipeTouchListener(ctx: Context) : OnTouchListener 

    private val gestureDetector: GestureDetector

    companion object 

        private val SWIPE_THRESHOLD = 100
        private val SWIPE_VELOCITY_THRESHOLD = 100
    

    init 
        gestureDetector = GestureDetector(ctx, GestureListener())
    

    override fun onTouch(v: View, event: MotionEvent): Boolean 
        return gestureDetector.onTouchEvent(event)
    

    private inner class GestureListener : SimpleOnGestureListener() 


        override fun onDown(e: MotionEvent): Boolean 
            return true
        

        override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean 
            var result = false
            try 
                val diffY = e2.y - e1.y
                val diffX = e2.x - e1.x
                if (Math.abs(diffX) > Math.abs(diffY)) 
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) 
                        if (diffX > 0) 
                            onSwipeRight()
                         else 
                            onSwipeLeft()
                        
                        result = true
                    
                 else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) 
                    if (diffY > 0) 
                        onSwipeBottom()
                     else 
                        onSwipeTop()
                    
                    result = true
                
             catch (exception: Exception) 
                exception.printStackTrace()
            

            return result
        


    

    open fun onSwipeRight() 

    open fun onSwipeLeft() 

    open fun onSwipeTop() 

    open fun onSwipeBottom() 

用法:

view.setOnTouchListener(object : OnSwipeTouchListener(context) 

    override fun onSwipeTop() 
        super.onSwipeTop()
    

    override fun onSwipeBottom() 
        super.onSwipeBottom()
    

    override fun onSwipeLeft() 
        super.onSwipeLeft()
    

    override fun onSwipeRight() 
        super.onSwipeRight()
    
)

open 关键字是我的重点...

【讨论】:

我们为什么要开课?? 在kotlin中,我们可以用abs()函数替换Math.abs【参考方案7】:

您不需要复杂的计算。 只需使用GestureDetector 类中的OnGestureListener 接口即可完成。

onFling 方法中,您可以像这样检测所有四个方向:

MyGestureListener.java:

import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;

public class MyGestureListener implements GestureDetector.OnGestureListener

    private static final long VELOCITY_THRESHOLD = 3000;

    @Override
    public boolean onDown(final MotionEvent e) return false; 

    @Override
    public void onShowPress(final MotionEvent e) 

    @Override
    public boolean onSingleTapUp(final MotionEvent e) return false; 

    @Override
    public boolean onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX,
                        final float distanceY) return false; 

    @Override
    public void onLongPress(final MotionEvent e) 

    @Override
    public boolean onFling(final MotionEvent e1, final MotionEvent e2,
                       final float velocityX,
                       final float velocityY)

        if(Math.abs(velocityX) < VELOCITY_THRESHOLD 
                    && Math.abs(velocityY) < VELOCITY_THRESHOLD)
            return false;//if the fling is not fast enough then it's just like drag
        

        //if velocity in X direction is higher than velocity in Y direction,
        //then the fling is horizontal, else->vertical
        if(Math.abs(velocityX) > Math.abs(velocityY))
            if(velocityX >= 0)
                Log.i("TAG", "swipe right");
            else//if velocityX is negative, then it's towards left
                Log.i("TAG", "swipe left");
            
        else
            if(velocityY >= 0)
                Log.i("TAG", "swipe down");
            else
                Log.i("TAG", "swipe up");
            
        

        return true;
    

用法:

GestureDetector mDetector = new GestureDetector(MainActivity.this, new MyGestureListener());

view.setOnTouchListener(new View.OnTouchListener()
    @Override
    public boolean onTouch(final View v, final MotionEvent event)
        return mDetector.onTouchEvent(event);
    
);

【讨论】:

筛选了这里所有的垃圾,你是对的,不需要过于复杂的事情——这个完美的工作 VELOCITY_THRESHOLD 不应该取决于屏幕密度吗? @GerritBeuze 不,Android 系统会处理这个问题。它通过velocityXvelocityYonFling 方法中发送正确的值。虽然您可以尝试看看哪个值最适合您的需求,但最终数字将是通用的。 这里的答案假设相反:它们没有缩放? :***.com/questions/18812479/… @GerritBeuze 这是因为他们通过计算手指移动的像素数量自己手动进行数学运算,这是错误的,因为它取决于像素密度。你应该像我一样只使用速度,速度几乎与 dpi 无关。【参考方案8】:

使用SwipeListView,让它为你处理手势检测。

【讨论】:

【参考方案9】:

要添加一个 onClick,这就是我所做的。

....
// in OnSwipeTouchListener class

private final class GestureListener extends SimpleOnGestureListener 

    .... // normal GestureListener  code

   @Override
    public boolean onSingleTapConfirmed(MotionEvent e) 
        onClick(); // my method
        return super.onSingleTapConfirmed(e);
    

 // end GestureListener class

    public void onSwipeRight() 
    

    public void onSwipeLeft() 
    

    public void onSwipeTop() 
    

    public void onSwipeBottom() 
    

    public void onClick() 
    


    // as normal
    @Override
    public boolean onTouch(View v, MotionEvent event) 
        return gestureDetector.onTouchEvent(event);


 // end OnSwipeTouchListener class

我正在使用 Fragments,因此使用 getActivity() 作为上下文。这就是我实现它的方式 - 并且它有效。


myLayout.setOnTouchListener(new OnSwipeTouchListener(getActivity()) 
            public void onSwipeTop() 
                Toast.makeText(getActivity(), "top", Toast.LENGTH_SHORT).show();
            
            public void onSwipeRight() 
                Toast.makeText(getActivity(), "right", Toast.LENGTH_SHORT).show();
            
            public void onSwipeLeft() 
                Toast.makeText(getActivity(), "left", Toast.LENGTH_SHORT).show();
            
            public void onSwipeBottom() 
                Toast.makeText(getActivity(), "bottom", Toast.LENGTH_SHORT).show();
            

            public void onClick()
                Toast.makeText(getActivity(), "clicked", Toast.LENGTH_SHORT).show();
            
        );

【讨论】:

【参考方案10】:

@Edward Brey's method 效果很好。如果有人还想复制和粘贴 OnSwipeTouchListener 的导入,他们是:

 import android.content.Context;
 import android.view.GestureDetector;
 import android.view.GestureDetector.SimpleOnGestureListener;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnTouchListener;

【讨论】:

【参考方案11】:

我的解决方案与上面的类似,但我将手势处理抽象为一个抽象类OnGestureRegisterListener.java,其中包括swipeclicklong click 手势。

OnGestureRegisterListener.java

public abstract class OnGestureRegisterListener implements View.OnTouchListener 

    private final GestureDetector gestureDetector;
    private View view;

    public OnGestureRegisterListener(Context context) 
        gestureDetector = new GestureDetector(context, new GestureListener());
    

    @Override
    public boolean onTouch(View view, MotionEvent event) 
        this.view = view;
        return gestureDetector.onTouchEvent(event);
    

    public abstract void onSwipeRight(View view);
    public abstract void onSwipeLeft(View view);
    public abstract void onSwipeBottom(View view);
    public abstract void onSwipeTop(View view);
    public abstract void onClick(View view);
    public abstract boolean onLongClick(View view);

    private final class GestureListener extends GestureDetector.SimpleOnGestureListener 

        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) 
            return true;
        

        @Override
        public void onLongPress(MotionEvent e) 
            onLongClick(view);
            super.onLongPress(e);
        

        @Override
        public boolean onSingleTapUp(MotionEvent e) 
            onClick(view);
            return super.onSingleTapUp(e);
        

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) 
            boolean result = false;
            try 
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) 
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) 
                        if (diffX > 0) 
                            onSwipeRight(view);
                         else 
                            onSwipeLeft(view);
                        
                        result = true;
                    
                
                else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) 
                    if (diffY > 0) 
                        onSwipeBottom(view);
                     else 
                        onSwipeTop(view);
                    
                    result = true;
                
             catch (Exception exception) 
                exception.printStackTrace();
            
            return result;
        

    

并像这样使用它。请注意,您也可以轻松传入 View 参数。

OnGestureRegisterListener onGestureRegisterListener = new OnGestureRegisterListener(this) 
    public void onSwipeRight(View view) 
        // Do something
    
    public void onSwipeLeft(View view) 
        // Do something
    
    public void onSwipeBottom(View view) 
        // Do something
    
    public void onSwipeTop(View view) 
        // Do something
    
    public void onClick(View view) 
        // Do something
    
    public boolean onLongClick(View view)  
        // Do something
        return true;
    
;

Button button = findViewById(R.id.my_button);
button.setOnTouchListener(onGestureRegisterListener);

【讨论】:

【参考方案12】:

我一直在做类似的事情,但仅限水平滑动

import android.content.Context
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View

abstract class OnHorizontalSwipeListener(val context: Context) : View.OnTouchListener     

    companion object 
         const val SWIPE_MIN = 50
         const val SWIPE_VELOCITY_MIN = 100
    

    private val detector = GestureDetector(context, GestureListener())

    override fun onTouch(view: View, event: MotionEvent) = detector.onTouchEvent(event)    

    abstract fun onRightSwipe()

    abstract fun onLeftSwipe()

    private inner class GestureListener : GestureDetector.SimpleOnGestureListener()     

        override fun onDown(e: MotionEvent) = true

        override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float)
            : Boolean 

            val deltaY = e2.y - e1.y
            val deltaX = e2.x - e1.x

            if (Math.abs(deltaX) < Math.abs(deltaY)) return false

            if (Math.abs(deltaX) < SWIPE_MIN
                    && Math.abs(velocityX) < SWIPE_VELOCITY_MIN) return false

            if (deltaX > 0) onRightSwipe() else onLeftSwipe()

            return true
        
    

然后它可以用于视图组件

private fun listenHorizontalSwipe(view: View) 
    view.setOnTouchListener(object : OnHorizontalSwipeListener(context!!) 
            override fun onRightSwipe() 
                Log.d(TAG, "Swipe right")
            

            override fun onLeftSwipe() 
                Log.d(TAG, "Swipe left")
            

        
    )

【讨论】:

【参考方案13】:

对@Mirek Rusin 的回答稍作修改,现在您可以检测到多点触控滑动。这段代码在 Kotlin 上:

class OnSwipeTouchListener(ctx: Context, val onGesture: (gestureCode: Int) -> Unit) : OnTouchListener 

private val SWIPE_THRESHOLD = 200
private val SWIPE_VELOCITY_THRESHOLD = 200

private val gestureDetector: GestureDetector

var fingersCount = 0

fun resetFingers() 
    fingersCount = 0


init 
    gestureDetector = GestureDetector(ctx, GestureListener())


override fun onTouch(v: View, event: MotionEvent): Boolean 
    if (event.pointerCount > fingersCount) 
        fingersCount = event.pointerCount
    
    return gestureDetector.onTouchEvent(event)


private inner class GestureListener : SimpleOnGestureListener() 

    override fun onDown(e: MotionEvent): Boolean 
        return true
    

    override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean 
        var result = false
        try 
            val diffY = e2.y - e1.y
            val diffX = e2.x - e1.x
            if (Math.abs(diffX) > Math.abs(diffY)) 
                if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) 
                    if (diffX > 0) 
                        val gesture = when (fingersCount) 
                            1 -> Gesture.SWIPE_RIGHT
                            2 -> Gesture.TWO_FINGER_SWIPE_RIGHT
                            3 -> Gesture.THREE_FINGER_SWIPE_RIGHT
                            else -> -1
                        
                        if (gesture > 0) 
                            onGesture.invoke(gesture)
                        
                     else 
                        val gesture = when (fingersCount) 
                            1 -> Gesture.SWIPE_LEFT
                            2 -> Gesture.TWO_FINGER_SWIPE_LEFT
                            3 -> Gesture.THREE_FINGER_SWIPE_LEFT
                            else -> -1
                        
                        if (gesture > 0) 
                            onGesture.invoke(gesture)
                        
                    
                    resetFingers()
                
             else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) 
                if (diffY > 0) 
                    val gesture = when (fingersCount) 
                        1 ->  Gesture.SWIPE_DOWN
                        2 -> Gesture.TWO_FINGER_SWIPE_DOWN
                        3 -> Gesture.THREE_FINGER_SWIPE_DOWN
                        else -> -1
                    
                    if (gesture > 0) 
                        onGesture.invoke(gesture)
                    
                 else 
                    val gesture = when (fingersCount) 
                        1 ->  Gesture.SWIPE_UP
                        2 -> Gesture.TWO_FINGER_SWIPE_UP
                        3 -> Gesture.THREE_FINGER_SWIPE_UP
                        else -> -1
                    
                    if (gesture > 0) 
                        onGesture.invoke(gesture)
                    
                
                resetFingers()
            
            result = true

         catch (exception: Exception) 
            exception.printStackTrace()
        

        return result
    

Gesture.SWIPE_RIGHT 和其他人是手势的唯一整数标识符,我在以后的活动中使用它来检测手势类型:

rootView?.setOnTouchListener(OnSwipeTouchListener(this, 
    gesture -> log(Gesture.parseName(this, gesture))
))

所以你在这里看到的手势是一个整数变量,它保存着我之前传递的值。

【讨论】:

谁能给我看一个例子,说明如何使用 Kotlin 检测同一视图的左滑动和正常点击。 如何在列表视图中使用它?它不会返回被触摸的视图的位置,那么你怎么知道哪一行被触摸了? 手势来自于什么进口? import android.gesture.Gesture 没有 SWIPE_RIGHT 全局变量。 为什么你没有写下这个手势的完整代码,把 SwipeDown、left、right 等放在哪里? 我们也可以检测到点击手势吗?【参考方案14】:

这个问题是多年前提出的。现在,有一个更好的解决方案:SmartSwipe:https://github.com/luckybilly/SmartSwipe

代码如下:

SmartSwipe.wrap(contentView)
        .addConsumer(new StayConsumer()) //contentView stay while swiping with StayConsumer
        .enableAllDirections() //enable directions as needed
        .addListener(new SimpleSwipeListener() 
            @Override
            public void onSwipeOpened(SmartSwipeWrapper wrapper, SwipeConsumer consumer, int direction) 
                //direction: 
                //  1: left
                //  2: right
                //  4: top
                //  8: bottom
            
        )
;

【讨论】:

在SmartSwipe内有很多SwipeConsumer用于不同的侧滑效果,如SlidingConsumer/StretchConsumer/SpaceConsumer/...等【参考方案15】:

@Mirek Rusin 的回答非常好。 但是,有一个小错误,需要修复 -

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) 
            boolean result = false;
            try 
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) 
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) 
                        if (diffX > 0) 
                            if (getOnSwipeListener() != null) 
                                getOnSwipeListener().onSwipeRight();
                            
                         else 
                            if (getOnSwipeListener() != null) 
                                getOnSwipeListener().onSwipeLeft();
                            
                        
                        result = true;
                    
                
                else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) 
                    if (diffY > 0) 
                        if (getOnSwipeListener() != null) 
                            getOnSwipeListener().onSwipeBottom();
                        
                     else 
                        if (getOnSwipeListener() != null) 
                            getOnSwipeListener().onSwipeTop();
                        
                    
                    result = true;
                

有什么区别?我们设置 result = true,仅当我们检查了所有要求(SWIPE_THRESHOLD 和 SWIPE_VELOCITY_THRESHOLD 都正常)。如果我们在某些要求没有达到的情况下放弃滑动,这很重要,我们必须在 OnSwipeTouchListener 的 onTouchEvent 方法中做一些事情!

【讨论】:

【参考方案16】:

这是用于检测手势方向的简单 Android 代码

MainActivity.javaactivity_main.xml中,编写如下代码:

MainActivity.java

import java.util.ArrayList;

import android.app.Activity;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.GestureOverlayView.OnGesturePerformedListener;
import android.gesture.GestureStroke;
import android.gesture.Prediction;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends Activity implements
        OnGesturePerformedListener 

    GestureOverlayView gesture;
    GestureLibrary lib;
    ArrayList<Prediction> prediction;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        lib = GestureLibraries.fromRawResource(MainActivity.this,
                R.id.gestureOverlayView1);
        gesture = (GestureOverlayView) findViewById(R.id.gestureOverlayView1);
        gesture.addOnGesturePerformedListener(this);
    

    @Override
    public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) 
        ArrayList<GestureStroke> strokeList = gesture.getStrokes();
        // prediction = lib.recognize(gesture);
        float f[] = strokeList.get(0).points;
        String str = "";

        if (f[0] < f[f.length - 2]) 
            str = "Right gesture";
         else if (f[0] > f[f.length - 2]) 
            str = "Left gesture";
         else 
            str = "no direction";
        
        Toast.makeText(getApplicationContext(), str, Toast.LENGTH_LONG).show();

    


activity_main.xml

<android.gesture.GestureOverlayView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android1="http://schemas.android.com/apk/res/android"
    xmlns:android2="http://schemas.android.com/apk/res/android"
    android:id="@+id/gestureOverlayView1"
    android:layout_
    android:layout_
    android1:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_
        android:layout_
        android:text="Draw gesture"
        android:textAppearance="?android:attr/textAppearanceMedium" />

</android.gesture.GestureOverlayView>

【讨论】:

【参考方案17】:
import android.content.Context
import android.view.GestureDetector
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener

/**
 * Detects left and right swipes across a view.
 */
class OnSwipeTouchListener(context: Context, onSwipeCallBack: OnSwipeCallBack?) : OnTouchListener 

    private var gestureDetector : GestureDetector
    private var onSwipeCallBack: OnSwipeCallBack?=null

    init 

        gestureDetector = GestureDetector(context, GestureListener())
        this.onSwipeCallBack = onSwipeCallBack!!
    
    companion object 

        private val SWIPE_DISTANCE_THRESHOLD = 100
        private val SWIPE_VELOCITY_THRESHOLD = 100
    

   /* fun onSwipeLeft() 

    fun onSwipeRight() */

    override fun onTouch(v: View, event: MotionEvent): Boolean 


        return gestureDetector.onTouchEvent(event)
    

    private inner class GestureListener : SimpleOnGestureListener() 

        override fun onDown(e: MotionEvent): Boolean 
            return true
        

        override fun onFling(eve1: MotionEvent?, eve2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean 
            try 
                if(eve1 != null&& eve2!= null) 
                    val distanceX = eve2?.x - eve1?.x
                    val distanceY = eve2?.y - eve1?.y
                    if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) 
                        if (distanceX > 0)
                            onSwipeCallBack!!.onSwipeLeftCallback()
                        else
                            onSwipeCallBack!!.onSwipeRightCallback()
                        return true
                    
                
            catch (exception:Exception)
                exception.printStackTrace()
            

            return false
        


    

【讨论】:

对于 Kotlin 你可以使用这样的东西: 用法:gv_calendar!!.setOnTouchListener(OnSwipeTouchListener(activity,onSwipeCallBack!!)) 请不要只是转储代码,包括对您的代码作用的解释。 什么是 OnSwipeCallBack?【参考方案18】:

这个问题仍然存在。添加以下类:

private class SwipeFirstTouchListener implements View.OnTouchListener 

    private final DirtyOnSwipeTouchListener swipe;
    private final View.OnTouchListener delegate;

    private SwipeFirstTouchListener(DirtyOnSwipeTouchListener swipe, View.OnTouchListener delegate) 
        this.swipe = swipe;
        this.delegate = delegate;
    

    @Override
    public boolean onTouch(View v, MotionEvent event) 
        if (!swipe.onTouch(v, event)) 
            // no a swipe, so lets try with the rest of the events
            return delegate.onTouch(v, event);
        
        return false;
    

private class DirtyOnSwipeTouchListener extends OnSwipeTouchListener 
    private boolean dirty = false;
    private OnSwipeTouchListener delegate;

    public DirtyOnSwipeTouchListener(Context ctx, OnSwipeTouchListener delegate) 
        super(ctx);

        this.delegate = delegate;
    

    private void reset() 
        dirty = false;
    

    public void onSwipeTop() 
        dirty = true;

        delegate.onSwipeTop();
    

    public void onSwipeRight() 
        dirty = true;
        delegate.onSwipeRight();
    

    public void onSwipeLeft() 
        dirty = true;
        delegate.onSwipeLeft();
    

    public void onSwipeBottom() 
        dirty = true;
        delegate.onSwipeBottom();
    

    @Override
    public boolean onTouch(View v, MotionEvent event) 
        try 
            super.onTouch(v, event);

            return dirty;
         finally 
            dirty = false;
        

    
;

和网上找到的一门课:

public class OnSwipeTouchListener implements OnTouchListener 
    
    private static final String TAG = OnSwipeTouchListener.class.getName();

    private final GestureDetector gestureDetector;

    public OnSwipeTouchListener(Context ctx) 
        gestureDetector = new GestureDetector(ctx, new GestureListener());
    

    @Override
    public boolean onTouch(View v, MotionEvent event) 
        return gestureDetector.onTouchEvent(event);
    

    private final class GestureListener extends GestureDetector.SimpleOnGestureListener 

        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) 
            return true;
        

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) 
            boolean result = false;
            try 
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) 
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) 
                        if (diffX > 0) 
                            onSwipeRight();
                         else 
                            onSwipeLeft();
                        
                        result = true;
                    
                 else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) 
                    if (diffY > 0) 
                        onSwipeBottom();
                     else 
                        onSwipeTop();
                    
                    result = true;
                
             catch (Exception exception) 
                Log.d(TAG, "Unexpected problem handling swipes, ignoring.", exception);
            
            return result;
        
    

    public void onSwipeRight() 
        // Do nothing
    

    public void onSwipeLeft() 
        // Do nothing
    

    public void onSwipeTop() 
        // Do nothing
    

    public void onSwipeBottom() 
        // Do nothing
    

然后像这样添加您自己的OnTouchListenerOnSwipeTouchListener

    DirtyOnSwipeTouchListener swipe = new DirtyOnSwipeTouchListener(this, new OnSwipeTouchListener(this) 
        public void onSwipeTop() 
            // your code here
        

        public void onSwipeRight() 
            // your code here
        

        public void onSwipeLeft() 
            // your code here
        

        public void onSwipeBottom() 
            // your code here
        
    );


    View.OnTouchListener toggleListener = new View.OnTouchListener() 
        public boolean onTouch(View v, MotionEvent event) 
            if (event.getAction() == MotionEvent.ACTION_UP) 
                // your code here

                return true;
             else if (event.getAction() == MotionEvent.ACTION_DOWN) 
                // your code here

                return true;
            
            return false;
        
    ;

    SwipeFirstTouchListener swipeFirstTouchListener = new SwipeFirstTouchListener(swipe, toggleListener);

    myView.setOnTouchListener(swipeFirstTouchListener);

【讨论】:

提供一个关于如何使用代码的完整示例会很棒! 添加了缺失的类和示例【参考方案19】:

如果您想在滑动列表项时显示一些带有操作的按钮,互联网上的很多库都有这种行为。 我实现了我在互联网上找到的库,我非常满意。它使用起来非常简单,而且速度非常快。我改进了原始库,并为项目单击添加了一个新的单击侦听器。我还添加了 font awesome 库 (http://fortawesome.github.io/Font-Awesome/),现在您可以简单地添加一个新项目标题并从 font awesome 指定图标名称。

Here是github链接

【讨论】:

【参考方案20】:
public class TranslatorSwipeTouch implements OnTouchListener

   private String TAG="TranslatorSwipeTouch";

   @SuppressWarnings("deprecation")
   private GestureDetector detector=new GestureDetector(new TranslatorGestureListener());

   @Override
   public boolean onTouch(View view, MotionEvent event)
   
     return detector.onTouchEvent(event);
   

private class TranslatorGestureListener extends SimpleOnGestureListener 

    private final int GESTURE_THRESHOULD=100;
    private final int GESTURE_VELOCITY_THRESHOULD=100;

    @Override
    public boolean onDown(MotionEvent e) 
        return true;
    

    @Override
    public boolean onFling(MotionEvent event1,MotionEvent event2,float velocityx,float velocityy)
    
        try
        
            float diffx=event2.getX()-event1.getX();
            float diffy=event2.getY()-event1.getY();

            if(Math.abs(diffx)>Math.abs(diffy))
            
                if(Math.abs(diffx)>GESTURE_THRESHOULD && Math.abs(velocityx)>GESTURE_VELOCITY_THRESHOULD)
                
                    if(diffx>0)
                    
                        onSwipeRight();
                    
                    else
                    
                        onSwipeLeft();
                    
                
            
            else
            
                if(Math.abs(diffy)>GESTURE_THRESHOULD && Math.abs(velocityy)>GESTURE_VELOCITY_THRESHOULD)
                
                    if(diffy>0)
                    
                         onSwipeBottom();
                    
                    else
                    
                        onSwipeTop();
                    
                
            
        
        catch(Exception e)
        
            Log.d(TAG, ""+e.getMessage());
        
        return false;           
    

    public void onSwipeRight()
    
        //Toast.makeText(this.getClass().get, "swipe right", Toast.LENGTH_SHORT).show();
        Log.i(TAG, "Right");
    
    public void onSwipeLeft()
    
        Log.i(TAG, "Left");
        //Toast.makeText(MyActivity.this, "swipe left", Toast.LENGTH_SHORT).show();
    

    public void onSwipeTop()
    
        Log.i(TAG, "Top");
        //Toast.makeText(MyActivity.this, "swipe top", Toast.LENGTH_SHORT).show();
    

    public void onSwipeBottom()
    
        Log.i(TAG, "Bottom");
        //Toast.makeText(MyActivity.this, "swipe bottom", Toast.LENGTH_SHORT).show();
       

  

 

【讨论】:

大量代码确实需要解释才能为读者提供价值。特别是抑制弃用警告的代码。你真的需要解释为什么在这种情况下代码是绝对必要的。【参考方案21】:

Edward Brey's answer 在 Kotlin 中的用法

 view.setOnTouchListener(object: OnSwipeTouchListener(this) 
      override fun onSwipeLeft() 
        super.onSwipeLeft()
      
      override fun onSwipeRight() 
        super.onSwipeRight()
      
    
 )

【讨论】:

【参考方案22】:

我知道它自 2012 年以来有点晚了,但我希望它对某人有所帮助,因为我认为它是比大多数答案更短、更清晰的代码:

view.setOnTouchListener((v, event) -> 
        
int action = MotionEventCompat.getActionMasked(event);

switch(action) 
    case (MotionEvent.ACTION_DOWN) :
        Log.d(DEBUG_TAG,"Action was DOWN");
        return true;

    case (MotionEvent.ACTION_MOVE) :
        Log.d(DEBUG_TAG,"Action was MOVE");
        return true;

    case (MotionEvent.ACTION_UP) :
        Log.d(DEBUG_TAG,"Action was UP");
        return true;

    case (MotionEvent.ACTION_CANCEL) :
        Log.d(DEBUG_TAG,"Action was CANCEL");
        return true;

    case (MotionEvent.ACTION_OUTSIDE) :
        Log.d(DEBUG_TAG,"Movement occurred outside bounds " +
                "of current screen element");
        return true;

    default :
        return super.onTouchEvent(event);

    );

当然你可以只留下相关的手势给你。

源代码:https://developer.android.com/training/gestures/detector

【讨论】:

以上是关于Android:如何处理从右到左的滑动手势的主要内容,如果未能解决你的问题,请参考以下文章

android seekbar 有没有从右到左的解决方法

UIPageViewController:从右到左的语言反转 .scroll 动画方向

Android从右到左textview滑动动画

如何在从右到左的位置(视差)连续移动 Sprite?

UINavigationController 覆盖从右到左的推送显示黑色背景

Python中从右到左的语言