滑动删除ListView
2016-01-13 14:08
232 查看
滑动删除ListView
实现原理: A、ListView的ListItem是一个容器,通过Scroller可以使得ListItem的子组件产生滚动。 B、需要通过手指所在的坐标来获取哪一个ListItem要滚动。 C、ListItem的滚动有两种情况:一种跟随手势滚动,另一种是惯性滚动 D、设置一个滚动的临界距离,如果手势滚动的距离超过临界距离,则继续惯性滚动删除,否则回滚,还原成初始状态 E、滚动结束后,要通过监听器(接口)来通知删除集合中的对象元素,并刷新重绘ListView。 1、如何找到需要滚动的ListItem? A、在dispatchTouchItem()方法中找到要滚动的ListItem B、获取手指所在的坐标 float x = event.getX(); float y = event.getY(); C、根据坐标获取ListItem在整个ListView中的索引位置 int p = ListView.pointToPosition(x, y); D、根据p找到ListView中可见区域的索引位置 int index = p - ListView.getFirstVisiblePosition(); E、根据index找到对应的ListView ViewGroup listItem = ListView.getChildAt(index); 2、实现思路 A、初始化,创建Scroller对象 public RemoveListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); scroller = new Scroller(context); } public RemoveListView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RemoveListView(Context context) { this(context, null); } B、定义删除完成后的监听器(接口) public interface OnListItemRemovedListener{ public void onListItemRemoved(int position); } C、手指按下后找到要滑动的ListItem @Override public boolean dispatchTouchEvent(MotionEvent ev) { int x = (int) ev.getX(); int y = (int) ev.getY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: // 获取手指所在的坐标对应的ListItem在整个ListView中的索引 int p = this.pointToPosition(x, y); // 根据p获取对应的可见区域中ListItem的索引 int index = p - this.getFirstVisiblePosition(); // 根据index开获取ListView中要滑动的子容器ListItem listItem = (ViewGroup) this.getChildAt(index); position = p; break; case MotionEvent.ACTION_MOVE: isScroll = true; break; case MotionEvent.ACTION_UP: isScroll = false; break; default: break; } return super.dispatchTouchEvent(ev); } D、ListItem的滑动(手势滑动和惯性滑动) @Override public boolean onTouchEvent(MotionEvent ev) { int x = (int) ev.getX(); int y = (int) ev.getY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: preX = x; preY = y; firstX = x; firstY = y; fingerUp = false; break; case MotionEvent.ACTION_MOVE: if (this.isScroll && listItem != null) { int curX = x; int curY = y; // 滑动ListItem listItem.scrollBy(-(curX - preX), 0); listItem.postInvalidate(); // 当前线段的结束点将成为下一条线段的起始点 preX = curX; preY = curY; } break; case MotionEvent.ACTION_UP: //获取ListItem移动的距离和方向 int movedDx = -(x - firstX); int meWidth = this.getMeasuredWidth(); //如果手势滑动的距离大于整个的一半,则删除,否则回滚 if(Math.abs(movedDx) >= meWidth / 2){ isForward = true; if(movedDx > 0){ //从右往左 scroller.startScroll(movedDx, 0, meWidth - Math.abs(movedDx), 0); }else{ //从左往右 scroller.startScroll(movedDx, 0, -(meWidth - Math.abs(movedDx)), 0); } }else{ isForward = false; scroller.startScroll(movedDx, 0, -movedDx, 0); } listItem.postInvalidate(); fingerUp = true; break; default: break; } return super.onTouchEvent(ev); } E、实现滑动效果 @Override public void computeScroll() { if(scroller.computeScrollOffset()){ listItem.scrollTo(scroller.getCurrX(), scroller.getCurrY()); postInvalidate(); //监听滑动是否结束(条件:滚动结束,手指要松开,惯性滑动) if(scroller.isFinished() && fingerUp && isForward){ if(onListItemRemovedListener != null){ onListItemRemovedListener.onListItemRemoved(position); } } } } 3、滑动删除的完整代码 A、RemovedListView.java package com.trkj.dept12_customer7_removelistview; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.ViewGroup; import android.widget.ListView; import android.widget.Scroller; public class RemoveListView extends ListView { // 要滑动删除的列表项 private ViewGroup listItem; // 是否可以滚动(手势滚动) private boolean isScroll; // 上一个点的坐标 private int preX, preY; //手指第一次按下时的坐标 private int firstX, firstY; // 惯性滚动 private Scroller scroller; // 手指是否松开 private boolean fingerUp = false; // true表示惯性滑动,false表示回滚 private boolean isForward = false; //删除的列表项的索引 private int position; //定义监听器 private OnListItemRemovedListener onListItemRemovedListener; public void setOnListItemRemovedListener( OnListItemRemovedListener onListItemRemovedListener) { this.onListItemRemovedListener = onListItemRemovedListener; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { int x = (int) ev.getX(); int y = (int) ev.getY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: // 获取手指所在的坐标对应的ListItem在整个ListView中的索引 int p = this.pointToPosition(x, y); // 根据p获取对应的可见区域中ListItem的索引 int index = p - this.getFirstVisiblePosition(); // 根据index开获取ListView中要滑动的子容器ListItem listItem = (ViewGroup) this.getChildAt(index); position = p; break; case MotionEvent.ACTION_MOVE: isScroll = true; break; case MotionEvent.ACTION_UP: isScroll = false; break; default: break; } return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { int x = (int) ev.getX(); int y = (int) ev.getY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: preX = x; preY = y; firstX = x; firstY = y; fingerUp = false; break; case MotionEvent.ACTION_MOVE: if (this.isScroll && listItem != null) { int curX = x; int curY = y; // 滑动ListItem listItem.scrollBy(-(curX - preX), 0); listItem.postInvalidate(); // 当前线段的结束点将成为下一条线段的起始点 preX = curX; preY = curY; } break; case MotionEvent.ACTION_UP: //获取ListItem移动的距离和方向 int movedDx = -(x - firstX); int meWidth = this.getMeasuredWidth(); //如果手势滑动的距离大于整个的一半,则删除,否则回滚 if(Math.abs(movedDx) >= meWidth / 2){ isForward = true; if(movedDx > 0){ //从右往左 scroller.startScroll(movedDx, 0, meWidth - Math.abs(movedDx), 0); }else{ //从左往右 scroller.startScroll(movedDx, 0, -(meWidth - Math.abs(movedDx)), 0); } }else{ isForward = false; scroller.startScroll(movedDx, 0, -movedDx, 0); } listItem.postInvalidate(); fingerUp = true; break; default: break; } return super.onTouchEvent(ev); } @Override public void computeScroll() { if(scroller.computeScrollOffset()){ listItem.scrollTo(scroller.getCurrX(), scroller.getCurrY()); postInvalidate(); //监听滑动是否结束(条件:滚动结束,手指要松开,惯性滑动) if(scroller.isFinished() && fingerUp && isForward){ if(onListItemRemovedListener != null){ onListItemRemovedListener.onListItemRemoved(position); } } } } public RemoveListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); scroller = new Scroller(context); } public RemoveListView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RemoveListView(Context context) { this(context, null); } /** * 监听是否删除的监听器 * @author 韬睿科技:李赞红 * */ public interface OnListItemRemovedListener{ public void onListItemRemoved(int position); } } B、item.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:background="@drawable/bg" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:background="#FFFFFF" android:padding="12dp" > <TextView android:id="@+id/name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="张震岳" android:textSize="14sp" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2" android:gravity="right" android:text="18978865434" android:textColor="#808080" android:textSize="12sp" /> </LinearLayout> </LinearLayout> C、phone.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.trkj.dept12_customer7_removelistview.RemoveListView android:id="@+id/lv" android:background="#CCCCCC" android:layout_width="match_parent" android:layout_height="match_parent" > </com.trkj.dept12_customer7_removelistview.RemoveListView> </LinearLayout> D、ListViewActivity.java package com.trkj.dept12_customer7_removelistview; import java.util.ArrayList; import android.app.Activity; import android.graphics.Point; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import android.widget.Toast; import com.trkj.dept12_customer7_removelistview.RemoveListView.OnListItemRemovedListener; public class ListViewActivity extends Activity { private RemoveListView lv; private ArrayList<String> data = new ArrayList<String>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.phone); for(int i = 0; i < 100; i ++){ data.add("张震岳" + i); } lv = (RemoveListView) findViewById(R.id.lv); lv.setOnListItemRemovedListener(new OnListItemRemovedListener() { @Override public void onListItemRemoved(int position) { Log.i("ListViewActivity", "position:" + position); data.remove(position); BaseAdapter adapter = (BaseAdapter) lv.getAdapter(); adapter.notifyDataSetChanged(); } }); // 定义适配器 MyAdapter adapter = new MyAdapter(); lv.setAdapter(adapter); } class MyAdapter extends BaseAdapter { @Override public int getCount() { return data.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = LayoutInflater.from(ListViewActivity.this).inflate( R.layout.item, null); TextView tvName = (TextView) v.findViewById(R.id.name); tvName.setText(data.get(position)); return v; } } }
4:效果图
相关文章推荐
- hbuider 框架分析
- Java IO流分析整理
- 第1章第2节练习题14 判断子序列
- easy-ui使用指南
- Codeforces Educational Codeforces Round 5 B. Dinner with Emma 暴力
- jQuery ajax 实现分页 kkpager插件
- UI高级 多线程
- CAS (10) —— JBoss EAP 6.4下部署CAS时出现错误exception.message=Error decoding flow execution的解决办法
- FC SAN - 光纤通道存储区域网络
- Android模块化编程之引用本地的aar
- 在论坛中出现的比较难的sql问题:33(递归 连续日期问题 )
- 把Java的class文件转为EXE文件的八种方法
- 支付宝参数
- Java IO最详解
- 1116: [POI2008]CLO|深度搜索
- 信必优再次入围“2015年在华跨国服务外包企业二十强”
- iPhone题(1)
- Java之美[从菜鸟到高手演变]之Java中的IO
- ThreadLocal用法详解和原理
- LeetCode 刷题: 合并两个有序链表 (merge two sorted list)