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

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

如何做到这一点?

【问题讨论】:

标签: android swipe gesture-recognition


【解决方案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 .
  • 感谢这些修改对我有用:stackoverflow.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 基础知识的好书或其他资源;否则,试图从 StackOverflow 拼凑解决方案将被证明是令人沮丧的。一个不错的选择是官方Training for Android developersStarting an Activity 部分讲述了您将放置setOnTouchListener 的位置(通常在onCreate 中)。 contextthis 指针(除非您正在创建片段)。
  • @Lara,我没试过,但你可以尝试覆盖 SimpleOnGestureListener.onSingleTapConfirmed
  • 谢谢,爱德华。我还发现将 onDown 的返回值从 true 更改为 false 可以解决问题。
  • @Signo,包含视图的活动提供上下文。在将视图添加到片段的常见情况下,使用Fragment.getActivity()
  • @coderVishal 根据您的目的,您可能会发现有用的SwipeRefreshLayoutSwipeRefreshLayoutBasic 示例或其变体之一。
【解决方案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 方法中发送正确的值。虽然您可以尝试看看哪个值最适合您的需求,但最终数字将是通用的。
  • 这里的答案假设相反:它们没有缩放? :stackoverflow.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_width="match_parent"
                  android:layout_height="match_parent"
                  android1:orientation="vertical" >
              
                  <TextView
                      android:id="@+id/textView1"
                      android:layout_width="wrap_content"
                      android:layout_height="wrap_content"
                      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

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-07-23
                      • 1970-01-01
                      • 2015-07-10
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多