滑动删除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:效果图