我在linearLayout内有一个带有回收站视图的活动,并且我试图检测此活动上的向上滑动和向下滑动手势。当前实现的问题是,如果将滑动侦听器添加到linearLayout,则不会触发它们;如果将它们添加到recyclerView,则它会左右滚动(因为它是水平的recyclerView),而不是检测滑动
这是我的代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/linear">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.cronlogy.hopstopandroid.activity.PlaceActivity"
tools:showIn="@layout/activity_place">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
滑动侦听器类:
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;
}
// 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() {
}
}
这就是我在活动中的称呼方式
recyclerView.setOnTouchListener(new OnSwipeTouchListener(this) {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onSwipeDown() {
Toast.makeText(PlaceActivity.this, "Down", Toast.LENGTH_SHORT).show();
}
@Override
public void onSwipeLeft() {
}
@Override
public void onSwipeUp() {
Toast.makeText(PlaceActivity.this, "Up", Toast.LENGTH_SHORT).show();
}
@Override
public void onSwipeRight() {
}
});
有人可以帮助我吗,如何在不滚动recyclerView中的项目的情况下检测滑动,或如何将滚动侦听器附加到其父视图。
答案 0 :(得分:0)
要在水平回收站视图上向上滑动,您需要一个自定义的RecyclerView,例如:
class CustomRecyclerView : RecyclerView {
private lateinit var mDetector: GestureDetectorCompat
// =================================================================================================================
// CONSTRUCTORS
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : super(
context,
attrs,
defStyleAttr
)
override fun onInterceptTouchEvent(e: MotionEvent?): Boolean {
if (!mDetector.onTouchEvent(e)) {
return super.onInterceptTouchEvent(e)
}
return onInterceptTouchEvent(e)
}
fun initDetector(swippeListener: SwipeListener) {
mDetector = GestureDetectorCompat(context, object : OnSwipeListener() {
override fun onSwipe(direction: Direction): Boolean {
if (direction == Direction.up) {
//Do something here (in my case I try to open a new submenu)
swippeListener.openSubmenu()
return true
} else if (direction == Direction.down) {
//Do something here (in my case I try to close a new submenu)
swippeListener.closeSubmenu()
return true
}
return false
}
})
}
}
SwipeListener(用于将操作返回给我的班级):
interface SwipeListener {
fun openSubmenu()
fun closeSubmenu()
}
然后您需要实现自己的OnSwipeListener:
我从以下位置获取此OnSwipeListener:
How to detect swipe direction between left/right and up/down
open class OnSwipeListener : GestureDetector.SimpleOnGestureListener() {
override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
// Grab two events located on the plane at e1=(x1, y1) and e2=(x2, y2)
// Let e1 be the initial event
// e2 can be located at 4 different positions, consider the following diagram
// (Assume that lines are separated by 90 degrees.)
//
//
// \ A /
// \ /
// D e1 B
// / \
// / C \
//
// So if (x2,y2) falls in region:
// A => it's an UP swipe
// B => it's a RIGHT swipe
// C => it's a DOWN swipe
// D => it's a LEFT swipe
//
val x1 = e1.x
val y1 = e1.y
val x2 = e2.x
val y2 = e2.y
val direction = getDirection(x1, y1, x2, y2)
return onSwipe(direction)
}
/** Override this method. The Direction enum will tell you how the user swiped. */
open fun onSwipe(direction: Direction): Boolean {
return false
}
/**
* Given two points in the plane p1=(x1, x2) and p2=(y1, y1), this method
* returns the direction that an arrow pointing from p1 to p2 would have.
* @param x1 the x position of the first point
* @param y1 the y position of the first point
* @param x2 the x position of the second point
* @param y2 the y position of the second point
* @return the direction
*/
fun getDirection(x1: Float, y1: Float, x2: Float, y2: Float): Direction {
val angle = getAngle(x1, y1, x2, y2)
return Direction.fromAngle(angle)
}
/**
*
* Finds the angle between two points in the plane (x1,y1) and (x2, y2)
* The angle is measured with 0/360 being the X-axis to the right, angles
* increase counter clockwise.
*
* @param x1 the x position of the first point
* @param y1 the y position of the first point
* @param x2 the x position of the second point
* @param y2 the y position of the second point
* @return the angle between two points
*/
fun getAngle(x1: Float, y1: Float, x2: Float, y2: Float): Double {
val rad = Math.atan2((y1 - y2).toDouble(), (x2 - x1).toDouble()) + Math.PI
return (rad * 180 / Math.PI + 180) % 360
}
enum class Direction {
up,
down,
left,
right;
companion object {
/**
* Returns a direction given an angle.
* Directions are defined as follows:
*
* Up: [45, 135]
* Right: [0,45] and [315, 360]
* Down: [225, 315]
* Left: [135, 225]
*
* @param angle an angle from 0 to 360 - e
* @return the direction of an angle
*/
fun fromAngle(angle: Double): Direction {
return if (inRange(angle, 45f, 135f)) {
Direction.up
} else if (inRange(angle, 0f, 45f) || inRange(angle, 315f, 360f)) {
Direction.right
} else if (inRange(angle, 225f, 315f)) {
Direction.down
} else {
Direction.left
}
}
/**
* @param angle an angle
* @param init the initial bound
* @param end the final bound
* @return returns true if the given angle is in the interval [init, end).
*/
private fun inRange(angle: Double, init: Float, end: Float): Boolean {
return angle >= init && angle < end
}
}
}
}