滑动删除

功能描述

实现一个左滑删除的功能,效果如下:
滑动删除

功能分析

  • ViewDragHelper:

    1. 用来分析touch事件的工具类
    2. 使用步骤

      1. 获取实例

        ViewDragHelper helper =ViewDragHelper.create(ViewGroup, CallBack);
      2. touch分析和监听

            @Override
        public boolean onTouchEvent(MotionEvent event) {
        mHelper.processTouchEvent(event);
        return true;
        }
      3. 实现自己的callBack

    3. touch:

      1. down
        1. tryCaptureView()
      2. move
        1. clampViewPositionHorizontal:水平移动的回调
      3. up
        1. onViewReleased()

代码实现

  • content.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">
    <TextView
        android:id="@+id/item_tv_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#33000000"
        android:gravity="center"
        android:textColor="@android:color/white"
        android:textSize="25sp"
        android:text="内容"/>

</LinearLayout>
  • delete.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="120dp"
              android:layout_height="80dp"
              android:orientation="vertical">

    <TextView
        android:id="@+id/item_tv_delete"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffff0000"
        android:gravity="center"
        android:text="删除"
        android:textColor="@android:color/white"
        android:textSize="25sp"/>
</LinearLayout>
  • 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:orientation="vertical">

    <com.cdw.sweep.SweepView
        android:id="@+id/item_sv"
        android:layout_width="match_parent"
        android:layout_height="80dp">
        <!--内容区-->
        <include layout="@layout/content"/>
        <!--删除区-->
        <include layout="@layout/delete"/>
    </com.cdw.sweep.SweepView>

</LinearLayout>
  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.cdw.sweep.MainActivity">

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </ListView>
</LinearLayout>
  • SweepView.java
package com.cdw.sweep;

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by dongwei on 2016/8/3.
 */
public class SweepView extends ViewGroup {
    private View mContentView;
    private View mDeleteView;
    private int mDeleteWidth;
    private ViewDragHelper mHelper;
    private boolean isOpened;
    private OnSweepListener mListener;

    public SweepView(Context context) {
        this(context, null);
    }

    public SweepView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mHelper = ViewDragHelper.create(this, new MyCallBack());
    }

    @Override
    protected void onFinishInflate() {
        mContentView = getChildAt(0);
        mDeleteView = getChildAt(1);

        LayoutParams params = mDeleteView.getLayoutParams();
        mDeleteWidth = params.width;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //测量内容
        mContentView.measure(widthMeasureSpec, heightMeasureSpec);
        //测量删除部分
        int deleteWidthMeasureSpec = MeasureSpec.makeMeasureSpec(mDeleteWidth, MeasureSpec.EXACTLY);
        mDeleteView.measure(deleteWidthMeasureSpec, heightMeasureSpec);
        //确定自己的高度
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        //布局内容区域
        mContentView.layout(0, 0, mContentView.getMeasuredWidth(), mContentView.getMeasuredHeight
                ());
        //布局删除部分
        mDeleteView.layout(mContentView.getMeasuredWidth(), 0, mContentView.getMeasuredWidth() +
                mDeleteWidth, mDeleteView.getMeasuredHeight());
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mHelper.processTouchEvent(event);
        return true;
    }

    class MyCallBack extends ViewDragHelper.Callback {

        /**
         * 是否分析view的touch
         *
         * @param child     触摸的view
         * @param pointerId touch的id
         * @return
         */
        @Override
        public boolean tryCaptureView(View child, int pointerId) {

            return child == mContentView || child == mDeleteView;
        }

        /**
         * 当touch移动后的回调
         *
         * @param child 谁移动了
         * @param left  child的左侧的边距
         * @param dx    增量的x
         * @return 确定要移动多少
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            if (child == mContentView) {
                if (left < 0 && -left > mDeleteWidth) {
                    return -mDeleteWidth;
                } else if (left > 0) {
                    return 0;
                }
            } else if (child == mDeleteView) {
                int measuredWidth = mContentView.getMeasuredWidth();
                if (left < measuredWidth - mDeleteWidth) {
                    return measuredWidth - mDeleteWidth;
                } else if (left > measuredWidth) {
                    return measuredWidth;
                }
            }

            return left;
        }

        /**
         * 当控件位置移动时的回调
         *
         * @param changedView 哪个view移动了
         * @param left        view的左上角的坐标
         * @param top         view的左上角的坐标
         * @param dx          x方向移动的增量
         * @param dy          y方向移动的增量
         */
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            invalidate();

            int contentWidth = mContentView.getMeasuredWidth();
            int contentHeight = mContentView.getMeasuredHeight();
            int deleteHeight = mDeleteView.getMeasuredHeight();
            if (changedView == mContentView) {
                //如果移动的是内容的view

                mDeleteView.layout(contentWidth + left, 0, contentWidth + left + mDeleteWidth,
                        deleteHeight);
            } else if (changedView == mDeleteView) {

                //int deleteWidth = mDeleteView.
                mContentView.layout(left - contentWidth, 0, left, contentHeight);
            }
        }

        /**
         * up时的回调
         *
         * @param releasedChild 松开了哪个view
         * @param xvel          x方向的速率
         * @param yvel          y方向的速率
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            int left = mContentView.getLeft();
            if (-left < mDeleteWidth / 2f) {
                //关闭
                close();
            } else {
                //打开
                open();
            }
            //invalidate();
        }
    }

    public void open() {
        isOpened = true;
        if (mListener != null) {
            mListener.onSweepChanged(SweepView.this, isOpened);
        }
        int contentWidth = mContentView.getMeasuredWidth();
        //布局内容区域
//                mContentView.layout(-mDeleteWidth, 0, contentWidth - mDeleteWidth, mContentView
//                        .getMeasuredHeight());
//                //布局删除部分
//                mDeleteView.layout(contentWidth - mDeleteWidth, 0, contentWidth, mDeleteView
//                        .getMeasuredHeight());
        //数据的模拟
        mHelper.smoothSlideViewTo(mContentView, -mDeleteWidth, 0);
        mHelper.smoothSlideViewTo(mDeleteView, contentWidth - mDeleteWidth, 0);


        ViewCompat.postInvalidateOnAnimation(SweepView.this);
    }

    public void close() {
        isOpened = false;
        if (mListener != null) {
            mListener.onSweepChanged(SweepView.this, isOpened);
        }
        //布局内容区域
//                mContentView.layout(0, 0, mContentView.getMeasuredWidth(), mContentView
//                        .getMeasuredHeight());
//                //布局删除部分
//                mDeleteView.layout(mContentView.getMeasuredWidth(), 0, mContentView
//                        .getMeasuredWidth() + mDeleteWidth, mDeleteView.getMeasuredHeight());

        //数据的模拟
        mHelper.smoothSlideViewTo(mContentView, 0, 0);
        mHelper.smoothSlideViewTo(mDeleteView, mContentView.getMeasuredWidth(), 0);

        ViewCompat.postInvalidateOnAnimation(SweepView.this);
    }

    @Override
    public void computeScroll() {
        if (mHelper.continueSettling(true)) {
            invalidate();
        }
    }

    public void setOnSweepListener(OnSweepListener listener) {
        this.mListener = listener;
    }

    public interface OnSweepListener {
        void onSweepChanged(SweepView view, boolean isOpened);
    }
}
  • mainActivity.java
package com.cdw.sweep;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class MainActivity extends Activity {
    private ListView mListView;
    private List<String> mDatas;
    private List<SweepView> mOpenedViews = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mListView = (ListView) findViewById(R.id.lv);

        //模拟数据
        mDatas = new ArrayList<>();
        for (int i = 0; i < 200; i++) {
            mDatas.add("第" + i + "条数据");
        }

        //给listView设置数据
        mListView.setAdapter(new MyAdapter());
    }

    class MyAdapter extends BaseAdapter {
        @Override
        public int getCount() {
            if (mDatas != null) {
                return mDatas.size();
            }
            return 0;
        }

        @Override
        public Object getItem(int position) {
            if (mDatas != null) {
                return mDatas.get(position);
            }
            return null;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            if (convertView == null) {
                //没有复用
                convertView = View.inflate(MainActivity.this, R.layout.item, null);
                //初始化Holder
                holder = new ViewHolder();
                //设置标记
                convertView.setTag(holder);
                //view的初始化
                holder.sv = (SweepView) convertView.findViewById(R.id.item_sv);
                holder.tvContent = (TextView) convertView.findViewById(R.id.item_tv_content);
                holder.tvDelete = (TextView) convertView.findViewById(R.id.item_tv_delete);
                holder.sv.setOnSweepListener(new SweepView.OnSweepListener() {
                    @Override
                    public void onSweepChanged(SweepView view, boolean isOpened) {
                        if (isOpened) {
                            //打开,记录下来
                            if (!mOpenedViews.contains(view)) {
                                mOpenedViews.add(view);
                            }
                        } else {
                            //移除
                            mOpenedViews.remove(view);
                        }
                    }
                });
            } else {
                //有复用
                holder = (ViewHolder) convertView.getTag();
            }
            //数据的加载
            final String data = mDatas.get(position);
            holder.tvContent.setText(data);

            holder.tvDelete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mDatas.remove(data);

                    //关闭所有打开的view
                    closeAll();

                    notifyDataSetChanged();
                }
            });
            return convertView;
        }
    }

    public void closeAll() {
        ListIterator<SweepView> iterator = mOpenedViews.listIterator();
        while (iterator.hasNext()) {
            SweepView view = iterator.next();
            view.close();
        }
    }

    class ViewHolder {
        SweepView sv;
        TextView tvContent;
        TextView tvDelete;
    }
}

项目链接https://github.com/ChenDongWei/Android/tree/0b4bc67b4381082e918ab5c04771c4324a92d430/sweep

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值