1、设计思路
在Scroller的应用--滑屏实现中使用Scroller实现滑屏效果,这里使用Scroller与ListView实现类似QQ滑动,然后点击删除功能,设计思路是Item使用Scroller实现滑动,ListView根据触摸判断是横向滑动还是竖直滑动,关于点击事件处理思路:对于View的onClick事件跟平常一样,里面针对OnItemClick做了处理,判断触摸距离来判断,如果小于5的话,在Item的onTouchEvent方法中的MotionEvent.ACTION_UP里面返回false,这样ListView里面的dispatchTouchEvent的super.dispatchTouchEvent(event)就会返回false,根据x,y获取当前position以及点击的view,调用super.performItemClick(view, position, view.getId());来告诉ListView出发onItemClick事件。
2、Item的代码
package com.jwzhangjie.scrollview; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; import android.widget.Scroller; public class ListItemDelete extends LinearLayout { private Scroller mScroller;// 滑动控制 private float mLastMotionX;// 记住上次触摸屏的位置 private int deltaX; private int back_width; private float downX; public ListItemDelete(Context context) { this(context, null); } public ListItemDelete(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context) { mScroller = new Scroller(context); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) {// 会更新Scroller中的当前x,y位置 scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int count = getChildCount(); for (int i = 0; i < count; i++) { measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec); if (i == 1) { back_width = getChildAt(i).getMeasuredWidth(); } } } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); float x = event.getX(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e("test", "item ACTION_DOWN"); mLastMotionX = x; downX = x; break; case MotionEvent.ACTION_MOVE: Log.e("test", back_width + " item ACTION_MOVE " + getScrollX()); deltaX = (int) (mLastMotionX - x); mLastMotionX = x; int scrollx = getScrollX() + deltaX; if (scrollx > 0 && scrollx < back_width) { scrollBy(deltaX, 0); } else if (scrollx > back_width) { scrollTo(back_width, 0); } else if (scrollx < 0) { scrollTo(0, 0); } break; case MotionEvent.ACTION_UP: Log.e("test", "item ACTION_UP"); int scroll = getScrollX(); if (scroll > back_width / 2) { scrollTo(back_width, 0); } else { scrollTo(0, 0); } if (Math.abs(x - downX) < 5) {// 这里根据点击距离来判断是否是itemClick return false; } break; case MotionEvent.ACTION_CANCEL: scrollTo(0, 0); break; } return true; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int margeLeft = 0; int size = getChildCount(); for (int i = 0; i < size; i++) { View view = getChildAt(i); if (view.getVisibility() != View.GONE) { int childWidth = view.getMeasuredWidth(); // 将内部子孩子横排排列 view.layout(margeLeft, 0, margeLeft + childWidth, view.getMeasuredHeight()); margeLeft += childWidth; } } } }
3、ListView的代码
package com.jwzhangjie.scrollview; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.ListView; public class ScrollListviewDelete extends ListView { private float minDis = 10; private float mLastMotionX;// 记住上次X触摸屏的位置 private float mLastMotionY;// 记住上次Y触摸屏的位置 private boolean isLock = false; public ScrollListviewDelete(Context context, AttributeSet attrs) { super(context, attrs); } /** * 如果一个ViewGroup的onInterceptTouchEvent()方法返回true,说明Touch事件被截获, * 子View不再接收到Touch事件,而是转向本ViewGroup的 * onTouchEvent()方法处理。从Down开始,之后的Move,Up都会直接在onTouchEvent()方法中处理。 * 先前还在处理touch event的child view将会接收到一个 ACTION_CANCEL。 * 如果onInterceptTouchEvent()返回false,则事件会交给child view处理。 */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (!isIntercept(ev)) { return false; } return super.onInterceptTouchEvent(ev); } @Override public boolean dispatchTouchEvent(MotionEvent event) { boolean dte = super.dispatchTouchEvent(event); if (MotionEvent.ACTION_UP == event.getAction() && !dte) {//onItemClick int position = pointToPosition((int)event.getX(), (int)event.getY()); View view = getChildAt(position); super.performItemClick(view, position, view.getId()); } return dte; } @Override // 处理点击事件,如果是手势的事件则不作点击事件 普通View public boolean performClick() { return super.performClick(); } @Override // 处理点击事件,如果是手势的事件则不作点击事件 ListView public boolean performItemClick(View view, int position, long id) { return super.performItemClick(view, position, id); } /** * 检测是ListView滑动还是item滑动 isLock 一旦判读是item滑动,则在up之前都是返回false */ private boolean isIntercept(MotionEvent ev) { float x = ev.getX(); float y = ev.getY(); int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e("test", "isIntercept ACTION_DOWN "+isLock); mLastMotionX = x; mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: Log.e("test", "isIntercept ACTION_MOVE "+isLock); if (!isLock) { float deltaX = Math.abs(mLastMotionX - x); float deltay = Math.abs(mLastMotionY - y); mLastMotionX = x; mLastMotionY = y; if (deltaX > deltay && deltaX > minDis) { isLock = true; return false; } } else { return false; } break; case MotionEvent.ACTION_UP: Log.e("test", "isIntercept ACTION_UP "+isLock); isLock = false; break; case MotionEvent.ACTION_CANCEL: Log.e("test", "isIntercept ACTION_CANCEL "+isLock); isLock = false; break; } return true; } }
4、Activity代码
package com.jwzhangjie.scrollview; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.ListView; public class ScrollListviewDelete extends ListView { private float minDis = 10; private float mLastMotionX;// 记住上次X触摸屏的位置 private float mLastMotionY;// 记住上次Y触摸屏的位置 private boolean isLock = false; public ScrollListviewDelete(Context context, AttributeSet attrs) { super(context, attrs); } /** * 如果一个ViewGroup的onInterceptTouchEvent()方法返回true,说明Touch事件被截获, * 子View不再接收到Touch事件,而是转向本ViewGroup的 * onTouchEvent()方法处理。从Down开始,之后的Move,Up都会直接在onTouchEvent()方法中处理。 * 先前还在处理touch event的child view将会接收到一个 ACTION_CANCEL。 * 如果onInterceptTouchEvent()返回false,则事件会交给child view处理。 */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (!isIntercept(ev)) { return false; } return super.onInterceptTouchEvent(ev); } @Override public boolean dispatchTouchEvent(MotionEvent event) { boolean dte = super.dispatchTouchEvent(event); if (MotionEvent.ACTION_UP == event.getAction() && !dte) {//onItemClick int position = pointToPosition((int)event.getX(), (int)event.getY()); View view = getChildAt(position); super.performItemClick(view, position, view.getId()); } return dte; } @Override // 处理点击事件,如果是手势的事件则不作点击事件 普通View public boolean performClick() { return super.performClick(); } @Override // 处理点击事件,如果是手势的事件则不作点击事件 ListView public boolean performItemClick(View view, int position, long id) { return super.performItemClick(view, position, id); } /** * 检测是ListView滑动还是item滑动 isLock 一旦判读是item滑动,则在up之前都是返回false */ private boolean isIntercept(MotionEvent ev) { float x = ev.getX(); float y = ev.getY(); int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e("test", "isIntercept ACTION_DOWN "+isLock); mLastMotionX = x; mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: Log.e("test", "isIntercept ACTION_MOVE "+isLock); if (!isLock) { float deltaX = Math.abs(mLastMotionX - x); float deltay = Math.abs(mLastMotionY - y); mLastMotionX = x; mLastMotionY = y; if (deltaX > deltay && deltaX > minDis) { isLock = true; return false; } } else { return false; } break; case MotionEvent.ACTION_UP: Log.e("test", "isIntercept ACTION_UP "+isLock); isLock = false; break; case MotionEvent.ACTION_CANCEL: Log.e("test", "isIntercept ACTION_CANCEL "+isLock); isLock = false; break; } return true; } }
5、XML代码
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.jwzhangjie.scrollview.ScrollListviewDelete android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <com.jwzhangjie.scrollview.ListItemDelete xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <LinearLayout android:id="@+id/front" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/bg_item_list_8" android:gravity="center" android:orientation="horizontal" > <TextView android:id="@+id/itemData" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="测试数据" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal" > <Button android:id="@+id/btnNao" android:layout_width="wrap_content" android:layout_height="match_parent" android:background="@drawable/bg_item_list_4" android:text="闹铃" /> <Button android:id="@+id/btnDelete" android:layout_width="wrap_content" android:layout_height="match_parent" android:background="@drawable/bg_item_list_5" android:text="删除" /> </LinearLayout> </com.jwzhangjie.scrollview.ListItemDelete>
6、界面效果
代码地址:https://github.com/jwzhangjie/-ScrollerDelete
时间: 2024-07-28 19:35:23