Scroller应用:ListView滑动删除

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

Scroller应用:ListView滑动删除的相关文章

【学习笔记】&quot;ListView滑动删除 ,仿腾讯QQ&quot;(二)

今天继续学习"鸿祥_"大神的写的"ListView滑动删除,仿腾讯QQ" . 1.关于dispatchTouchEvent 之前,只用过onTouchEvent,现在才知道一个Touch事件居然如此复杂.OK,集中精力,且看下文(本段内容主要参考Android dispatchTouchEvent介绍): 一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_

【学习笔记】&quot;ListView滑动删除 ,仿腾讯QQ&quot;(一)

今天看了"鸿祥_"大神的写的"ListView滑动删除,仿腾讯QQ" .大神果然是大神,第一篇文章,我就看不懂,好多知识需要学习. 1.  文中的一个声明:private LayoutInflater mInflater; 什么是LayoutInflater? 答:主要参考了这篇文章 Android LayoutInflater详解 在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById().不同点是LayoutInfl

【学习笔记】&quot;ListView滑动删除 ,仿腾讯QQ&quot;(三)

今天继续学习"鸿祥_"大神的写的"ListView滑动删除,仿腾讯QQ" . 今天,我准备学习并理清QQListView的逻辑. 1.自定义ListView 先看看布局文件activity_main.xml: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.c

实现listview滑动删除功能_Android源码

实现listview滑动删除功能,动作流畅. 下载地址:http://www.devstore.cn/code/info/579.html

Android 结合滑动控件ListView滑动删除

一转眼就15年了,希望大家15年升职加薪走上人生巅峰 这篇博客是结合上一篇ListView滑动删除之Viewgroup打造滑动控件(修正版)博客所完成的,先上个效果图吧. 其实实现起来并不复杂 1,解决滑动冲突 因为我们的自定义滑动控件和ListView本身的滑动事件会产生各种冲突,所以我们可以自定义ListView并重写onInterceptTouchEvent方法. 我们先来了解一下android事件的分发,当用户触摸屏幕时会先去调用ViewGroup的dispatchTouchEvent方

Android ListView滑动删除及响应事件详解

目标:实现类似QQ,微信的消息列表滑动删除 具体操作: 1. 主页面布局 首先在布局文件(本例是activity_main.xml)中引入ListView控件,并指定id(如下代码中黑体部分). <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" andr

Android ListView 侧滑效果实现(滑动展开、滑动删除)

转载请注明出处:http://blog.csdn.net/lonelyroamer/article/details/42439875 项目需要ListView滑动删除的效果,首先肯定是拿来主义,在网上搜了一遍,发现这样的东西真不少,比较有名的Github上的SwipeListView.但是个人尝试了一下,发现它的bug不少,并且达不到我想要的效果.于是又尝试了一下其他的例子,发现基本效果都有,但是都有不少问题.要么事件冲突,要么OnItemListView或者某个Button响应不了.没办法,只

ListView + PopupWindow实现滑动删除

原文:ListView滑动删除 ,仿腾讯QQ(鸿洋_) 文章实现的功能是:在ListView的Item上从右向左滑时,出现删除按钮,点击删除按钮把Item删除. 看过文章后,感觉没有必要把dispatchTouchEvent()和onTouchEvent()两个方法都重写,只要重写onTouchEvent就好了.于是对代码作了一些调整: public class MyListView extends ListView { private static final String TAG = "My

【安卓笔记】滑动删除示例

本文将使用上篇文章介绍的Scroller类来完成一个比较常见的效果--滑动删除效果. 代码如下: simpleSwipeListView: package cn.edu.chd.simpleswipelistview; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.v