自定义控件--滑动删除

1.应用场景:替换item长按删除
2.实现逻辑:
a.自定义一个可以滑动的布局;

b.将该布局放入adapter的布局中,需要处理滑动冲突;

3.目录结构:


4.java代码:

4.1 SwipeLayoutManager.java

package com.weizh.swipedelete.manager;

import com.weizh.swipedelete.widget.SwipeLayout;

/**
 * Created by weizh_000 on 2016/8/24.
 */

public class SwipeLayoutManager {

    private static SwipeLayoutManager swipeLayoutManager = new SwipeLayoutManager();
    private SwipeLayout currentLayout;

    public static SwipeLayoutManager getInstance(){
        return swipeLayoutManager;
    }

    //记录当前打开的是哪一个swipeLayout
    public void setCurrentLayout(SwipeLayout swipeLayout){
        this.currentLayout = swipeLayout;
    }

    //清除记录
    public void clearCurrentLayout(){
        currentLayout=null;
    }

    //关闭记录中的swipelayout
    public void closeSwipeLayout(){
        if (currentLayout!=null){
            currentLayout.close();
        }
    }

    //判断是否可以左右滑动swipelayout
    public boolean isShouldOpen(SwipeLayout swipeLayout){
        if (currentLayout==null){
            //说明无记录,可以打开
            return true;
        }else {
            //说明有记录,
            //记录的是自己,可以左右滑动
            //记录的是别的swipelayout,则不能滑动
            return currentLayout==swipeLayout;
        }
    }

    public void resumeSwipeLayout() {
        if(currentLayout!=null){
            currentLayout.resume();
        }
    }
}

4.2 SwipeLayout.java

package com.weizh.swipedelete.widget;

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.widget.FrameLayout;

import com.weizh.swipedelete.manager.SwipeLayoutManager;

/**
 * Created by weizh_000 on 2016/8/23.
 */

public class SwipeLayout extends FrameLayout {
    private View contentView;//item内容区域的view
    private View deleteView;//delete区域的view
    private int contentWidth;//内容区域的宽度
    private int deleteWidth;//delete区域的宽度
    private int deleteHeight;//delete区域的高度
    private ViewDragHelper dragHelper;
    private float downX;
    private float downY;
    private SwipeState currentState;//当前状态是默认是关闭状态

    public SwipeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public SwipeLayout(Context context) {
        super(context);
        init();
    }

    public SwipeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        dragHelper = ViewDragHelper.create(this, callback);
        currentState = SwipeState.Close;
    }


    enum SwipeState {
        Open, Close;
    }


    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        contentView = getChildAt(0);
        deleteView = getChildAt(1);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        contentWidth = contentView.getMeasuredWidth();
        deleteWidth = deleteView.getMeasuredWidth();
        deleteHeight = deleteView.getMeasuredHeight();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        contentView.layout(0, 0, contentWidth, deleteHeight);
        deleteView.layout(contentView.getRight(), 0, contentView.getRight() + deleteWidth, deleteHeight);
    }

    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child == contentView || child == deleteView;
        }

        @Override
        public int getViewHorizontalDragRange(View child) {
            return deleteWidth;
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            if (child == contentView) {
                if (left < -deleteWidth) left = -deleteWidth;
                if (left > 0) left = 0;
            } else if (child == deleteView) {
                if (left < contentWidth - deleteWidth) left = contentWidth - deleteWidth;
                if (left > contentWidth) left = contentWidth;
            }
            return left;
        }

        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
//            super.onViewPositionChanged(changedView, left, top, dx, dy);
            //做伴随移动
            if (changedView == contentView) {
                deleteView.layout(deleteView.getLeft() + dx, 0, deleteView.getRight() + dx, deleteHeight);
            } else if (changedView == deleteView) {
                contentView.layout(contentView.getLeft() + dx, 0, contentView.getRight() + dx, deleteHeight);
            }
            //判断开关逻辑
            if (contentView.getLeft() == 0) {
                //说明state应更改为关闭
                currentState = SwipeState.Close;
                //清空已打开swipelayout记录
                SwipeLayoutManager.getInstance().clearCurrentLayout();
            } else if (contentView.getLeft() == -deleteWidth) {
                //说明state应更改为打开
                currentState = SwipeState.Open;
                //记录已打开swipelayout
                SwipeLayoutManager.getInstance().setCurrentLayout(SwipeLayout.this);
            }

        }

        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
            if (contentView.getLeft() < -deleteWidth / 2) {
                //应该打开
                open();
            } else {
                //应该关闭
                close();
            }
        }
    };

    //打开swipelayout
    private void open() {
        dragHelper.smoothSlideViewTo(contentView, -deleteWidth, 0);
        ViewCompat.postInvalidateOnAnimation(SwipeLayout.this);
    }

    //关闭swipelayout
    public void close() {
        dragHelper.smoothSlideViewTo(contentView, 0, 0);
        ViewCompat.postInvalidateOnAnimation(SwipeLayout.this);
    }
//恢复swipelayout至初始位置
    public void resume() {
        contentView.layout(0,0,contentWidth,deleteHeight);
        deleteView.layout(contentView.getRight(),0,contentView.getRight()+deleteWidth,deleteHeight);
    }



    @Override
    public void computeScroll() {
        if (dragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(SwipeLayout.this);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //让dragHelper决定是否拦截事件
        boolean b = dragHelper.shouldInterceptTouchEvent(ev);
        if (!SwipeLayoutManager.getInstance().isShouldOpen(this)) {
            b = true;//将事件传递给onTouchEvent
            //当前swipelayout不能滑动,先关闭swipelayout
            SwipeLayoutManager.getInstance().closeSwipeLayout();
            //请求父类不要拦截事件
            requestDisallowInterceptTouchEvent(true);
        }
        return b;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //如果有已打开的swipelayout,则先关闭
        if (!SwipeLayoutManager.getInstance().isShouldOpen(this)) {
            //消费掉触摸事件
            return true;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                downY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float moveX = event.getX();
                float moveY = event.getY();
                float delatX = moveX - downX;
                float delatY = moveY - downY;
                if (Math.abs(delatX) > Math.abs(delatY)) {
                    //禁止listview拦截事件
                    requestDisallowInterceptTouchEvent(true);
                }
                downX = moveX;
                downY = moveY;
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        //交给dragHelper处理触摸事件
        dragHelper.processTouchEvent(event);
        return true;
    }
}

4.3 MainActivity.java

package com.weizh.swipedelete;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

import com.weizh.swipedelete.manager.SwipeLayoutManager;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private ListView lvListView;
    private ArrayList<String> strings;

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

    private void initData() {
        //1.设置数据
        strings = new ArrayList<>();
        for (int i=0;i<30;i++) {
            strings.add("name - "+i);
        }
        lvListView.setAdapter(new MyAdapter());
        lvListView.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView absListView, int scrollState) {
                if(scrollState==SCROLL_STATE_TOUCH_SCROLL){
                    //垂直滑动则需要关闭已经打开的swipelayout
                    SwipeLayoutManager.getInstance().closeSwipeLayout();
                }
            }

            @Override
            public void onScroll(AbsListView absListView, int i, int i1, int i2) {

            }
        });
    }

    private void initView() {
         lvListView=(ListView) findViewById(R.id.lv_list);
    }

    class MyAdapter extends BaseAdapter{

        @Override
        public int getCount() {
            return strings.size();
        }

        @Override
        public Object getItem(int i) {
            return null;
        }

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

        @Override
        public View getView(final int position, View convertView, ViewGroup viewGroup) {
            ViewHolder holder=null;
            if (convertView==null){
                convertView=View.inflate(getApplicationContext(),R.layout.list_item,null);
                holder=new ViewHolder();
                holder.tvName= (TextView) convertView.findViewById(R.id.tv_name);
                holder.tvDelete= (TextView) convertView.findViewById(R.id.tv_delete);
                convertView.setTag(holder);
            }else {
                holder= (ViewHolder) convertView.getTag();
            }
            holder.tvName.setText(strings.get(position));
            //给delete textview设置点击事件
            holder.tvDelete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //恢复swipelayout至初始位置
                    SwipeLayoutManager.getInstance().resumeSwipeLayout();
                    //清除swipelayout打开记录
                    SwipeLayoutManager.getInstance().clearCurrentLayout();
                    strings.remove(position);//从集合中移除对应的条目数据
                    notifyDataSetChanged();//通知数据更新
                }
            });
            return convertView;
        }
    }

    class ViewHolder{

        public TextView tvName;
        public TextView tvDelete;
    }
}

5. 布局文件

5.1 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.weizh.swipedelete.MainActivity">
    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/lv_list"
        ></ListView>

</LinearLayout>

5.2 layout_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="80dp"
    android:paddingLeft="15dp"
    android:background="#33666666"
    android:gravity="center_vertical"
    android:orientation="horizontal" >
    
    <ImageView android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/head_1"/>
    
    <TextView android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="#99000000"
        android:id="@+id/tv_name"
        android:layout_marginLeft="10dp"
        android:textSize="20sp"
        android:text="名称"/>

</LinearLayout>

5.3 layout_delete.xml

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

    <TextView android:layout_width="100dp"
        android:layout_height="match_parent"
        android:textSize="18sp"
        android:textColor="#ffffff"
        android:gravity="center"
        android:background="#aa000000"
        android:text="Call"/>
    
    <TextView android:layout_width="100dp"
        android:layout_height="match_parent"
        android:textSize="18sp"
        android:textColor="#ffffff"
        android:id="@+id/tv_delete"
        android:gravity="center"
        android:background="#eeff0000"
        android:text="Delete"/>

</LinearLayout>

5.4 list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<com.weizh.swipedelete.widget.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/sd_delete"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">


        <include layout="@layout/layout_content" />

        <include layout="@layout/layout_delete" />

</com.weizh.swipedelete.widget.SwipeLayout>

6.运行效果图:


7.源码地址:https://github.com/Jszgw/SwipeDelete

微信小程序-wepy-侧滑删除组件,支持自定义内容区在最近的微信小程序开发过程中需要用到侧滑删除的功能,微信小程序官方是没有提供这样的组件,再加上我们的微信小程序使用的是wepy组件开发框架开发的,wepy也没有提供这样的组件,之前也在github上搜索这方面的组件,没有发现合适的,当时只发现了一个开源的:https://github.com/GeoffZhu/wepy-swipe-delete 只不过该组件功能单一已经被作者废弃了,无奈自己动手撸了一个侧滑删除组件,现在把它开源出来吧。Requirementswepy: "^1.7.3"支持功能和特点自定义内容区域:支持之定义内容区域,组件内使用 slot占位。自定义滚动高度:可以自定义scroll-view的高度,默认为屏幕的高度。自定义menu :如果默认的menu样式不喜欢可以自定义,也可以显示或者隐藏指定的menu。左右滑动:支持左右滑动也可以设置只左右或者右滑。效果如下:       如何使用目前支持两种使用模式:1.page页面模式优点:可定制化高,扩展性强。 缺点:集成复杂,代码复用性差。2.component 组件模式优点:集成简单,代码复用性强,减少包的大小。 缺点:可定制到低。不建议使用page页面模式,下面详细介绍component 组件模式的使用如何使用// 导入组件import SwipeDeleteView from '@/components/wepy-swipe-delete-view'// 声明组件  components = {       swipeDeleteSwipeDeleteView     }       // 引用组件   <template>   <swipeDelete :list.sync="list">       <view class="item">{{item.userName}}</view>     </swipeDelete>   </template>配置如下:<swipeDelete   :list.sync="list"                :scrollHeight="scrollHeight"                @deleteTap.user="deleteTap"                @deleteLongTap.user="deleteLongTap"                @editTap.user="editTap"                @editLongTap.user="editLongTap"                @addTap.user="addTap"                @addLongTap.user="addLongTap"                @markTap.user="markTap"                @markLongTap.user="markLongTap">属性属性说明备注list要显示的列表的原始数据,最好是加上.sync这样可以异步传值必传scrollHeight设置scroll-view的高度,默认为屏幕高度选传deleteTap.user删除menu单击事件回调必要时传deleteLongTap.user删除menu长按事件回调必要时传editTap.user编辑menu单击事件回调必要时传editLongTap.user编辑menu长按事件回调必要时传addTap.user添加menu单击事件回调必要时传addLongTap.user添加menu长按事件回调必要时传markTap.user标记menu单击事件回调必要时传markLongTap.user标记menu长按事件回调必要时传每个点击事件或者长按事件都会返回两个参数methods = {       deleteTap(view, item) {         console.log(item)         view.deleteItem()       },       deleteLongTap(view, item) {         console.log(item)         wx.showModal({           title: '提示',           content: '确定要删除吗?',           success: function (res) {             if (res.confirm) {               view.deleteItem()             } else {               view.closeItem()             }           }         })       }    }view :view 是SwipeDeleteView对象的本身,可以通过view来做一些其他操作,如:删除当前的itemitem : item 就是当前操作的原始数据,可以通过item获取真正需要的数据当前SwipeDeleteView对外暴露的函数有:函数名称函数说明参数deleteItem删除当前操作的item(原始数据 view)都会被删除不需要参数closeItem关闭当前操作的item,原始数据不变不需要参数网络异步加载更新如果使用的网络异步加载完成以后,还需要更新下组件,不然会出现无法侧滑的情况。导致原因:原始数据更新以后组件内部无法监听到,这样就不能获取到左右menu的宽度,所以不能侧滑解决办法:this.$invoke('swipeDelete', 'update'); swipeDelete必须和 components = {swipeDelete: SwipeDeleteView} 同名。代码如下:// 模拟网络加载延迟2秒钟    let that = this      setTimeout(function () {        for (let i = 0; i < 20; i ) {          let msg = {}          msg.userName = ''   '用户'   (i   1)          msg.msgText = '您有新的消息'          msg.color = that.buildRandomColor()          msg.height = that.buildRandomHeight()          msg.headerImg = options.avatarUrl          that.list.push(msg)        }        wx.hideLoading()        // 更新组件        that.$invoke('swipeDelete', 'update')        that.$apply()      }, 2000)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值