滑动删除ListView

滑动删除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:效果图
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值