侧滑recyclerView的置顶和删除

先看UI效果图
demo

主要是实现侧滑操作,通过ViewDragHelper来实现侧滑。

  1. item的布局文件
<?xml version="1.0" encoding="utf-8"?>
<com.hu.test.wight.SwipeListLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                                 android:id="@+id/sll_msg"
                                                 android:layout_width="match_parent"
                                                 android:layout_height="wrap_content" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="center_vertical"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/tv_top"
            android:layout_width="80dp"
            android:layout_height="match_parent"
            android:background="#66ff0000"
            android:gravity="center"
            android:text="置顶" />

        <TextView
            android:id="@+id/tv_delete"
            android:layout_width="80dp"
            android:layout_height="match_parent"
            android:background="#330000ff"
            android:gravity="center"
            android:text="删除" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/ll_msg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center_vertical"
        android:background="#66ffffff"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center_vertical"
            android:padding="15dp"
            android:text="" />
    </LinearLayout>

</com.hu.test.wight.SwipeListLayout>
这里用到的就是自定义空间,继承FrameLayout布局,并进行位置处理,看布局显示位置如下:


由上面的图看出,必须要对布局进行代码控制,才能让侧滑布局在布局外面(FrameLayout仅仅通过xml不好实现)

这里先了解下View生命周期的顺序:
View的生命周期
注意到 onFinishInflate()这个方法,指的是:当系统解析完View之后调用。所以可以在这里提前获取组件的View

     @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        //布局只支持拥有两个子布局
        hiddenView = getChildAt(0); // 得到隐藏按钮的linearlayout
        itemView = getChildAt(1); // 得到最上层的linearlayout
    }

然后在onSizeChanged()这里测量view的宽高

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 测量子View的长和宽
        itemWidth = itemView.getMeasuredWidth();
        itemHeight = itemView.getMeasuredHeight();
        hiddenViewWidth = hiddenView.getMeasuredWidth();
        hiddenViewHeight = hiddenView.getMeasuredHeight();
    }

调用onLayout()来确定初始化得位置,达到侧滑布局在屏幕外面

 @Override
    protected void onLayout(boolean changed, int left, int top, int right,
                            int bottom) {
        layout(Status.Close);//初始化位置,状态为关闭
    }

 /**
     *确定侧滑区域的位置
     * @param status
     */
    private void layout(Status status) {
        if (status == Status.Close) {
            hiddenView.layout(itemWidth, 0, itemWidth + hiddenViewWidth,
                    itemHeight);
            itemView.layout(0, 0, itemWidth, itemHeight);
        } else {
            hiddenView.layout(itemWidth - hiddenViewWidth, 0, itemWidth,
                    itemHeight);
            itemView.layout(-hiddenViewWidth, 0, itemWidth - hiddenViewWidth,
                    itemHeight);
        }
    }

2.ViewDragHelper的使用
创建实例: 两个参数:一个操作的view,和回调callback

 public SwipeListLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDragHelper = ViewDragHelper.create(this, callback);
    }

使用ViewDragHelper先把onTouch事件处理好,以免忘记了。

 // 让ViewDragHelper来处理触摸事件
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        if (action == MotionEvent.ACTION_CANCEL) {
            mDragHelper.cancel();
            return false;
        }
        return mDragHelper.shouldInterceptTouchEvent(ev);
    }

    // 让ViewDragHelper来处理触摸事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mDragHelper.processTouchEvent(event);
        return true;
    };

Callback的回调处理:

 // ViewDragHelper的回调
    Callback callback = new Callback() {

        @Override
        public boolean tryCaptureView(View view, int arg1) {
            return view == itemView;
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            if (child == itemView) {
                if (left > 0) {
                    return 0;
                } else {
                    left = Math.max(left, -hiddenViewWidth);
                    return left;
                }
            }
            return 0;
        }

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

        @Override
        public void onViewPositionChanged(View changedView, int left, int top,
                                          int dx, int dy) {
            if (itemView == changedView) {
                hiddenView.offsetLeftAndRight(dx);
            }
            // 有时候滑动很快的话 会出现隐藏按钮的linearlayout没有绘制的问题
            // 为了确保绘制成功 调用 invalidate
            invalidate();
        }

        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
        //失去焦点的回弹方法
            // 向右滑xvel为正 向左滑xvel为负
            if (releasedChild == itemView) {
                if (xvel == 0
                        && Math.abs(itemView.getLeft()) > hiddenViewWidth / 2.0f) {
                    open(smooth);
                } else if (xvel < 0) {
                    open(smooth);
                } else {
                    close(smooth);
                }
            }
        }

    };
自定义的全部代码如下:
package com.hu.test.wight;

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

/**
 * 侧滑Layout
 */
public class SwipeListLayout extends FrameLayout {

    private View hiddenView;
    private View itemView;
    private int hiddenViewWidth;
    private ViewDragHelper mDragHelper;
    private int hiddenViewHeight;
    private int itemWidth;
    private int itemHeight;
    private OnSwipeStatusListener listener;
    private Status status = Status.Close;
    private boolean smooth = true;

    public static final String TAG = "SlipListLayout";

    // 状态
    public enum Status {
        Open, Close
    }

    /**
     * 设置侧滑状态
     *
     * @param status
     *            状态 Open or Close
     * @param smooth
     *            若为true则有过渡动画,否则没有
     */
    public void setStatus(Status status, boolean smooth) {
        this.status = status;
        if (status == Status.Open) {
            open(smooth);
        } else {
            close(smooth);
        }
    }

    public void setOnSwipeStatusListener(OnSwipeStatusListener listener) {
        this.listener = listener;
    }

    /**
     * 是否设置过渡动画
     *
     * @param smooth
     */
    public void setSmooth(boolean smooth) {
        this.smooth = smooth;
    }

    public interface OnSwipeStatusListener {

        /**
         * 当状态改变时回调
         *
         * @param status
         */
        void onStatusChanged(Status status);

        /**
         * 开始执行Open动画
         */
        void onStartCloseAnimation();

        /**
         * 开始执行Close动画
         */
        void onStartOpenAnimation();

    }

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

    public SwipeListLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDragHelper = ViewDragHelper.create(this, callback);
    }

    // ViewDragHelper的回调
    Callback callback = new Callback() {

        @Override
        public boolean tryCaptureView(View view, int arg1) {
            return view == itemView;
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            if (child == itemView) {
                if (left > 0) {
                    return 0;
                } else {
                    left = Math.max(left, -hiddenViewWidth);
                    return left;
                }
            }
            return 0;
        }

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

        @Override
        public void onViewPositionChanged(View changedView, int left, int top,
                                          int dx, int dy) {
            if (itemView == changedView) {
                hiddenView.offsetLeftAndRight(dx);
            }
            // 有时候滑动很快的话 会出现隐藏按钮的linearlayout没有绘制的问题
            // 为了确保绘制成功 调用 invalidate
            invalidate();
        }

        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            // 向右滑xvel为正 向左滑xvel为负
            if (releasedChild == itemView) {
                if (xvel == 0
                        && Math.abs(itemView.getLeft()) > hiddenViewWidth / 2.0f) {
                    open(smooth);
                } else if (xvel < 0) {
                    open(smooth);
                } else {
                    close(smooth);
                }
            }
        }

    };
    private Status preStatus = Status.Close;

    /**
     * 侧滑关闭
     *
     * @param smooth
     *            为true则有平滑的过渡动画
     */
    private void close(boolean smooth) {
        preStatus = status;
        status = Status.Close;
        if (smooth) {
            if (mDragHelper.smoothSlideViewTo(itemView, 0, 0)) {
                if (listener != null) {
                    Log.i(TAG, "start close animation");
                    listener.onStartCloseAnimation();
                }
                ViewCompat.postInvalidateOnAnimation(this);
            }
        } else {
            layout(status);
        }
        if (listener != null && preStatus == Status.Open) {
            Log.i(TAG, "close");
            listener.onStatusChanged(status);
        }
    }

    /**
     *
     * @param status
     */
    private void layout(Status status) {
        if (status == Status.Close) {
            hiddenView.layout(itemWidth, 0, itemWidth + hiddenViewWidth,
                    itemHeight);
            itemView.layout(0, 0, itemWidth, itemHeight);
        } else {
            hiddenView.layout(itemWidth - hiddenViewWidth, 0, itemWidth,
                    itemHeight);
            itemView.layout(-hiddenViewWidth, 0, itemWidth - hiddenViewWidth,
                    itemHeight);
        }
    }

    /**
     * 侧滑打开
     *
     * @param smooth
     *            为true则有平滑的过渡动画
     */
    private void open(boolean smooth) {
        preStatus = status;
        status = Status.Open;
        if (smooth) {
            if (mDragHelper.smoothSlideViewTo(itemView, -hiddenViewWidth, 0)) {
                if (listener != null) {
                    Log.i(TAG, "start open animation");
                    listener.onStartOpenAnimation();
                }
                ViewCompat.postInvalidateOnAnimation(this);
            }
        } else {
            layout(status);
        }
        if (listener != null && preStatus == Status.Close) {
            Log.i(TAG, "open");
            listener.onStatusChanged(status);
        }
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        // 开始执行动画
        if (mDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    // 让ViewDragHelper来处理触摸事件
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        if (action == MotionEvent.ACTION_CANCEL) {
            mDragHelper.cancel();
            return false;
        }
        return mDragHelper.shouldInterceptTouchEvent(ev);
    }

    // 让ViewDragHelper来处理触摸事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mDragHelper.processTouchEvent(event);
        return true;
    };

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        hiddenView = getChildAt(0); // 得到隐藏按钮的linearlayout
        itemView = getChildAt(1); // 得到最上层的linearlayout
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 测量子View的长和宽
        itemWidth = itemView.getMeasuredWidth();
        itemHeight = itemView.getMeasuredHeight();
        hiddenViewWidth = hiddenView.getMeasuredWidth();
        hiddenViewHeight = hiddenView.getMeasuredHeight();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
                            int bottom) {
        layout(Status.Close);
    }

}

3 , 处理置顶和删除功能
recycleView 用的BaseQuickAdapter的适配库,习惯了

package com.hu.test.adapter;

import android.content.Context;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.hu.test.R;
import com.hu.test.wight.SwipeListLayout;

import java.util.List;

/**
 * Created by TT on 2017/9/7.
 */

public class MesageAdapter extends BaseQuickAdapter<String> {


    private  Context mContext;
    private int position;
    private List<String> data;
    private SwipeListLayout swipeListLayout;

    public MesageAdapter(Context context , List<String> data) {
        super(R.layout.item_msg, data);
        this.mContext=context;
        this.data=data;
    }


    @Override
    protected void convert(final BaseViewHolder holder, final String item) {
        swipeListLayout = holder.getView(R.id.sll_msg);
        holder.setText(R.id.tv_name,item)
                .setOnClickListener(R.id.tv_top, new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        btnOnClickListen.onTopListen(holder.getLayoutPosition(),swipeListLayout);
                        Log.e("position==",holder.getLayoutPosition()+"");
                    }
                })
                .setOnClickListener(R.id.tv_delete, new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        btnOnClickListen.onDeleteListen(holder.getLayoutPosition(),swipeListLayout);
                        Log.e("position==",holder.getLayoutPosition()+"");

                    }
                })
                .setOnClickListener(R.id.ll_msg, new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        Toast.makeText(mContext,"正常区域",Toast.LENGTH_SHORT).show();
                        Log.e("position==",holder.getLayoutPosition()+"");
                    }
                });
    }

    //定义回调借口,将置顶按钮和删除按钮设置回调
    public interface  BtnOnClickListen{
        void onTopListen(int position ,SwipeListLayout swipeListLayout);
        void onDeleteListen(int position ,SwipeListLayout swipeListLayout);
    }

    /**
     * 点击,设置回调
     */
    public BtnOnClickListen btnOnClickListen;

    /**
     * 设置监听接口
     * @param btnOnClickListen
     */
    public void setBtnOnClickListen(BtnOnClickListen btnOnClickListen) {
        this.btnOnClickListen = btnOnClickListen;
    }
}
package com.hu.test.ui.drawer.message;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.ImageView;
import android.widget.Toast;

import com.hu.test.R;
import com.hu.test.adapter.MesageAdapter;
import com.hu.test.ui.BaseActivity;
import com.hu.test.wight.SwipeListLayout;

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

/**
 * Created by TT on 2017/6/29.
 */
public class MessageActivity extends BaseActivity {

    private ImageView iv;
    private RecyclerView recyclerView;

    private List<String> stringList = new ArrayList<>();
    private MesageAdapter mesageAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_message);
        showContentView();
        recyclerView = (RecyclerView) findViewById(R.id.rc_msg);
        recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
        initData();
    }

    private void initData() {
        for (int i = 0; i < 10; i++) {
            stringList.add("dassssssd"+i*10000);
        }

        mesageAdapter = new MesageAdapter(this,stringList);
        recyclerView.setAdapter(mesageAdapter);

        //置顶和删除的回调处理
        mesageAdapter.setBtnOnClickListen(new MesageAdapter.BtnOnClickListen() {
            @Override
            public void onTopListen(int position, SwipeListLayout swipeListLayout) {
                swipeListLayout.setStatus(SwipeListLayout.Status.Close, true);
                //置顶操作就是:删除当前item,再加入到集合顶部,刷新就行
                String zhiding = stringList.get(position);
                stringList.remove(position);
                mesageAdapter.notifyItemRemoved(position);
                mesageAdapter.notifyItemRangeChanged(0,stringList.size()-position);

                stringList.add(0,"置顶"+zhiding);
                mesageAdapter.notifyItemInserted(0);
                mesageAdapter.notifyItemRangeChanged(0,stringList.size()-0);
                Toast.makeText(getApplicationContext(),"置顶",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onDeleteListen(int position, SwipeListLayout swipeListLayout) {
                swipeListLayout.setStatus(SwipeListLayout.Status.Close, true);
                    Toast.makeText(getApplicationContext(),"删除=="+"当前条目"+position,Toast.LENGTH_SHORT).show();
                stringList.remove(position);
                mesageAdapter.notifyItemRemoved(position);
                mesageAdapter.notifyItemRangeChanged(0,stringList.size()-position);


            }
        });
    }
}

当前效果就完成了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值