仿QQ侧滑删除Item效果Demo

来源:互联网 发布:c语言 external 编辑:程序博客网 时间:2024/05/24 05:03

Demo 传送门

关于仿QQ侧滑删除Item的代码,还是有许多实现的方式的,就比如上篇博客写的利用HorizontalScrollView嵌套来实现,但是体验效果却并不是特别的理想。之后也尝试了另外的一种方式来达到这种侧滑删除的效果,特别的理想,现在就把代码粘贴上来。


接下是来实现效果的几个步骤:
1.新建一个项目MainActivity类文件以及activity_main.xml布局文件,代码如下:

MainActivity类文件

package com.lw.widget.slideitem;import android.content.Context;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;import android.widget.Toast;public class MainActivity extends AppCompatActivity {    Context context;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        RecyclerView    recyclerView  = (RecyclerView) findViewById(R.id.rv_data_list);        recyclerView.setLayoutManager(new LinearLayoutManager(this));        recyclerView.addItemDecoration(new LinearItemDecoration()); //设置分割线样式        SlideItemAdapter slideitemadapter = new SlideItemAdapter(context);        recyclerView.setAdapter(slideitemadapter);        slideitemadapter.setItemClickListener(new ItemClickListener() {            @Override            public void onItemClick(View view, int postion) {                Toast.makeText(getApplication(),"商品"+(postion+1),Toast.LENGTH_LONG).show();            }        });    }}

activity_main.xml布局文件

<?xml version="1.0" encoding="utf-8"?><RelativeLayout 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"    tools:context="com.lw.widget.slideitem.MainActivity"    android:background="#f6f6f6">    <android.support.v7.widget.RecyclerView        android:id="@+id/rv_data_list"        android:layout_width="match_parent"        android:layout_height="match_parent"        >    </android.support.v7.widget.RecyclerView></RelativeLayout>

2.根据下边的这张图,创建关键类及接口:

这里写图片描述

SlideItemAdapter 适配器

package com.lw.widget.slideitem;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.LinearLayout;import android.widget.TextView;import java.util.ArrayList;import java.util.List;/** * Created by Administrator on 2016-07-05. */public class SlideItemAdapter  extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements ItemSlideHelper.Callback{    private RecyclerView mRecyclerView;    private List<Integer> colors;    private Context mContext;    private ItemClickListener mItemClickListener;    public void setItemClickListener(ItemClickListener mItemClickListener) {        this.mItemClickListener = mItemClickListener;    }    public SlideItemAdapter(Context context) {        // 初始化        mContext = context;        // 填充list的内容模拟数据,否则应该异步执行        colors = new ArrayList<Integer>();        for (int i = 0; i < 15; i++) {            colors.add(R.color.colorAccent);        }    }     @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_slide, parent, false);         return new TextVH(view);    }    @Override    public int getItemCount() {        return colors.size();    }    @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {//        String text  = "item: " + position;        TextVH textVH = (TextVH) holder;        textVH.item_layout.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (null != mItemClickListener) {                    mItemClickListener.onItemClick(v, position);                }            }        });//        textVH.textView.setText(text);        textVH.tv_delete.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Log.i("kkkk","删除按钮有效==========="+position);                colors.remove(position);                // 刷新ListView内容//                notifyDataSetChanged();                notifyItemChanged(colors.size());            }        });    }    @Override    public void onAttachedToRecyclerView(RecyclerView recyclerView) {        super.onAttachedToRecyclerView(recyclerView);        mRecyclerView = recyclerView;        mRecyclerView.addOnItemTouchListener(new ItemSlideHelper(mRecyclerView.getContext(), this));    }    @Override    public int getHorizontalRange(RecyclerView.ViewHolder holder) {        if(holder.itemView instanceof LinearLayout){            ViewGroup viewGroup = (ViewGroup) holder.itemView;            if(viewGroup.getChildCount() == 2){                return viewGroup.getChildAt(1).getLayoutParams().width;            }        }        return 0;    }    @Override    public RecyclerView.ViewHolder getChildViewHolder(View childView) {        return mRecyclerView.getChildViewHolder(childView);    }    @Override    public View findTargetView(float x, float y) {        return mRecyclerView.findChildViewUnder(x, y);    }}class TextVH extends RecyclerView.ViewHolder{    TextView    textView,tv_delete;    LinearLayout item_layout;    public TextVH(View itemView) {        super(itemView);        textView = (TextView) itemView.findViewById(R.id.tv_text);        tv_delete = (TextView) itemView.findViewById(R.id.tv_delete);        item_layout = (LinearLayout) itemView.findViewById(R.id.item_layout);    }}

item_slide.xml适配器布局文件

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="horizontal"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#f6f6f6"    >    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginTop="5dp"        android:background="#fff"        >        <!--商品详情-->        <LinearLayout            android:id="@+id/item_layout"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:orientation="horizontal"            android:gravity="center|left"            android:background="#fff">            <LinearLayout                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:layout_marginTop="10dp"                android:layout_marginBottom="10dp"                android:layout_weight="7"                android:layout_marginLeft="15dp"                android:paddingTop="1dp"                android:paddingBottom="1dp"                android:paddingLeft="1dp"                android:paddingRight="1dp"                android:orientation="horizontal"                android:gravity="center|left"                android:background="#f6f6f6">                <LinearLayout                    android:layout_width="match_parent"                    android:layout_height="match_parent"                    android:orientation="horizontal"                    android:gravity="center"                    android:background="#fff">                    <ImageView                        android:layout_width="wrap_content"                        android:layout_height="wrap_content"                        android:layout_marginTop="10dp"                        android:layout_marginBottom="10dp"                        android:background="@mipmap/liucha"/>                </LinearLayout>            </LinearLayout>            <LinearLayout                android:layout_width="match_parent"                android:layout_height="match_parent"                android:layout_weight="3"                android:layout_marginLeft="15dp"                android:layout_marginRight="10dp"                android:orientation="vertical"                android:gravity="center_horizontal|right">                <LinearLayout                    android:layout_width="match_parent"                    android:layout_height="wrap_content"                    android:layout_marginTop="10dp"                    android:orientation="horizontal"                    android:gravity="center|left">                    <TextView                        android:layout_width="wrap_content"                        android:layout_height="wrap_content"                        android:textColor="#292421"                        android:text="挑战不一样的fell,大茶网青春小茶合包  (五包)"                        android:textSize="15dp"/>                </LinearLayout>                <LinearLayout                    android:layout_width="match_parent"                    android:layout_height="wrap_content"                    android:layout_marginTop="10dp"                    android:orientation="horizontal"                    android:gravity="center_horizontal|left">                    <LinearLayout                        android:layout_width="match_parent"                        android:layout_height="wrap_content"                        android:layout_weight="1"                        android:orientation="horizontal"                        android:gravity="center_horizontal|left">                        <TextView                            android:id="@+id/tv_text"                            android:layout_width="wrap_content"                            android:layout_height="wrap_content"                            android:layout_marginBottom="5dp"                            android:text="数量:"                            android:textColor="#808A87"                            android:textSize="12dp"/>                        <TextView                            android:layout_width="wrap_content"                            android:layout_height="wrap_content"                            android:layout_marginLeft="5dp"                            android:layout_marginBottom="5dp"                            android:text="1"                            android:textColor="#808A87"                            android:textSize="12dp"/>                    </LinearLayout>                    <LinearLayout                        android:layout_width="match_parent"                        android:layout_height="wrap_content"                        android:layout_weight="1"                        android:orientation="horizontal"                        android:gravity="center_horizontal|right">                        <TextView                            android:layout_width="wrap_content"                            android:layout_height="wrap_content"                            android:layout_marginBottom="5dp"                            android:text="单价:"                            android:textColor="#808A87"                            android:textSize="12dp"/>                        <TextView                            android:layout_width="wrap_content"                            android:layout_height="wrap_content"                            android:layout_marginBottom="5dp"                            android:layout_marginLeft="5dp"                            android:text="¥172.00"                            android:textColor="#808A87"                            android:textSize="12dp"/>                    </LinearLayout>                </LinearLayout>            </LinearLayout>        </LinearLayout>    </LinearLayout>    <LinearLayout        android:layout_width="80dp"        android:layout_height="match_parent"        >        <TextView            android:id="@+id/tv_delete"            android:layout_width="wrap_content"            android:layout_height="match_parent"            android:layout_marginTop="5dp"            android:layout_weight="1"            android:text="删除"            android:background="@android:color/holo_red_light"            android:gravity="center"            android:textColor="@android:color/white"            />    </LinearLayout></LinearLayout>

LinearItemDecoration 类文件

package com.lw.widget.slideitem;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Rect;import android.support.annotation.ColorInt;import android.support.v7.widget.RecyclerView;import android.util.TypedValue;import android.view.View;public class LinearItemDecoration extends RecyclerView.ItemDecoration{    private Paint   mPaint;    private int     mColor;    public LinearItemDecoration(@ColorInt int color) {        mPaint = new Paint();        mPaint.setColor(color);        mPaint.setAntiAlias(true);        mPaint.setDither(true);    }    public LinearItemDecoration() {        this(0);    }    @Override    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {        int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, parent.getResources().getDisplayMetrics());        RecyclerView.LayoutManager  layoutManager = parent.getLayoutManager();        View childView ;        RecyclerView.LayoutParams   layoutParams;        int childCount = layoutManager.getChildCount();        Rect  drawRect = new Rect();        int top,left,right,bottom;        for(int childIndex = 0 ; childIndex < childCount - 1; childIndex++){            childView = layoutManager.getChildAt(childIndex);            layoutParams = (RecyclerView.LayoutParams) childView.getLayoutParams();            top = childView.getBottom() + layoutParams.bottomMargin;            left = childView.getLeft() + layoutParams.leftMargin + childView.getPaddingLeft();            right = childView.getRight() - childView.getPaddingRight() - layoutParams.rightMargin;            bottom = top + height;            drawRect.set(left,top,  right, bottom);            c.drawRect(drawRect, mPaint);        }    }    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, parent.getResources().getDisplayMetrics());        outRect.set(0, 0, 0,  height);    }}

ItemSlideHelper类文件

package com.lw.widget.slideitem;import android.animation.Animator;import android.animation.ObjectAnimator;import android.content.Context;import android.graphics.Rect;import android.support.v4.view.GestureDetectorCompat;import android.support.v4.view.MotionEventCompat;import android.support.v7.widget.RecyclerView;import android.util.Log;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;import android.view.ViewConfiguration;/** * 帮助显示左滑菜单 */public class ItemSlideHelper implements RecyclerView.OnItemTouchListener, GestureDetector.OnGestureListener {    private static final String TAG = "ItemSwipeHelper";    private final int DEFAULT_DURATION = 200;    private View mTargetView;    private int mActivePointerId;    private int mTouchSlop;    private int mMaxVelocity;    private int mMinVelocity;    private int mLastX;    private int mLastY;    private boolean mIsDragging;    private Animator mExpandAndCollapseAnim;    private GestureDetectorCompat mGestureDetector;    private Callback mCallback;    public ItemSlideHelper(Context context, Callback callback) {        this.mCallback = callback;        //手势用于处理fling        mGestureDetector = new GestureDetectorCompat(context, this);        ViewConfiguration configuration = ViewConfiguration.get(context);        mTouchSlop = configuration.getScaledTouchSlop();        mMaxVelocity = configuration.getScaledMaximumFlingVelocity();        mMinVelocity = configuration.getScaledMinimumFlingVelocity();    }    @Override    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {        Log.d(TAG, "onInterceptTouchEvent: " + e.getAction());        int action =  MotionEventCompat.getActionMasked(e);        int x = (int) e.getX();        int y = (int) e.getY();        //如果RecyclerView滚动状态不是空闲targetView不是空        if(rv.getScrollState() != RecyclerView.SCROLL_STATE_IDLE){            if(mTargetView != null){                //隐藏已经打开                smoothHorizontalExpandOrCollapse(DEFAULT_DURATION / 2);                mTargetView = null;            }            return false;        }        //如果正在运行动画 ,直接拦截什么都不做        if(mExpandAndCollapseAnim != null && mExpandAndCollapseAnim.isRunning()){            return true;        }        boolean needIntercept =  false;        switch (action) {            case MotionEvent.ACTION_DOWN:                mActivePointerId = MotionEventCompat.getPointerId(e, 0);                mLastX = (int) e.getX();                mLastY = (int) e.getY();                /*                * 如果之前有一个已经打开的项目,当此次点击事件没有发生在右侧的菜单中则返回TRUE,                * 如果点击的是右侧菜单那么返回FALSE这样做的原因是因为菜单需要响应Onclick                * */                if(mTargetView != null){                    return !inView(x, y);                }                //查找需要显示菜单的view;                mTargetView = mCallback.findTargetView(x, y);                break;            case MotionEvent.ACTION_MOVE:                int deltaX = (x - mLastX);                int deltaY = (y - mLastY);                if(Math.abs(deltaY) > Math.abs(deltaX))                    return false;                //如果移动距离达到要求,则拦截                needIntercept = mIsDragging = mTargetView != null && Math.abs(deltaX) >= mTouchSlop;                break;            case MotionEvent.ACTION_CANCEL:            case MotionEvent.ACTION_UP:                /*                * 走这是因为没有发生过拦截事件                * */                if(isExpanded()){                    if (inView(x, y)) {                      // 如果走这那行这个ACTION_UP的事件会发生在右侧的菜单中                        Log.d(TAG, "click item");                    }else{                        //拦截事件,防止targetView执行onClick事件                        needIntercept = true;                    }                    //折叠菜单                    smoothHorizontalExpandOrCollapse(DEFAULT_DURATION / 2);                }                mTargetView = null;                break;        }        return  needIntercept ;    }    private boolean isExpanded() {        return mTargetView != null &&  mTargetView.getScrollX() == getHorizontalRange();    }    private boolean isCollapsed() {        return mTargetView != null && mTargetView.getScrollX() == 0;    }    /*    * 根据targetView的scrollX计算出targetView的偏移,这样能够知道这个point    * 是在右侧的菜单中    * */    private boolean inView(int x, int y) {        if (mTargetView == null)            return false;        int scrollX = mTargetView.getScrollX();        int left = mTargetView.getWidth() - scrollX;        int top = mTargetView.getTop();        int right = left + getHorizontalRange() ;        int bottom = mTargetView.getBottom();        Rect rect = new Rect(left, top, right, bottom);        return rect.contains(x, y);    }    @Override    public void onTouchEvent(RecyclerView rv, MotionEvent e) {        Log.d(TAG, "onTouchEvent: " + e.getAction());        if(mExpandAndCollapseAnim != null && mExpandAndCollapseAnim.isRunning() || mTargetView == null)            return;        //如果要响应fling事件设置将mIsDragging设为false        if (mGestureDetector.onTouchEvent(e)) {            mIsDragging = false;            return;        }        int x = (int) e.getX();        int y = (int) e.getY();        int action =  MotionEventCompat.getActionMasked(e);        switch (action) {            case MotionEvent.ACTION_DOWN:                //RecyclerView 不会转发这个Down事件                break;            case MotionEvent.ACTION_MOVE:                int deltaX = (int) (mLastX - e.getX());                if(mIsDragging) {                    horizontalDrag(deltaX);                }                mLastX = x;                break;            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL:                 if(mIsDragging){                    if(!smoothHorizontalExpandOrCollapse(0) && isCollapsed())                        mTargetView = null;                    mIsDragging = false;                 }                break;        }    }    @Override    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {    }    /**     *     * 根据touch事件来滚动View的scrollX     *     * @param delta     */    private void horizontalDrag(int delta) {        int scrollX = mTargetView.getScrollX();        int scrollY = mTargetView.getScrollY();        if ((scrollX + delta) <= 0) {            mTargetView.scrollTo(0, scrollY);            return;        }        int horRange = getHorizontalRange();        scrollX += delta;        if (Math.abs(scrollX) < horRange) {            mTargetView.scrollTo(scrollX, scrollY);        } else {            mTargetView.scrollTo(horRange, scrollY);        }    }    /**     * 根据当前scrollX的位置判断是展开还是折叠     *     * @param velocityX     *  如果不等于0那么这是一次fling事件,否则是一次ACTION_UP或者ACTION_CANCEL     */    private boolean smoothHorizontalExpandOrCollapse(float velocityX) {        int scrollX = mTargetView.getScrollX();        int scrollRange = getHorizontalRange();        if (mExpandAndCollapseAnim != null)            return false;        int to = 0;        int duration = DEFAULT_DURATION;        if (velocityX == 0) {            //如果已经展一半,平滑展开            if (scrollX > scrollRange / 2) {                to = scrollRange;            }        } else {            if (velocityX > 0)                to = 0;            else                to = scrollRange;            duration = (int) ((1.f - Math.abs(velocityX) / mMaxVelocity) * DEFAULT_DURATION);        }        if(to == scrollX)            return false;        mExpandAndCollapseAnim = ObjectAnimator.ofInt(mTargetView, "scrollX", to);        mExpandAndCollapseAnim.setDuration(duration);        mExpandAndCollapseAnim.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {            }            @Override            public void onAnimationEnd(Animator animation) {                mExpandAndCollapseAnim = null;                if (isCollapsed())                    mTargetView = null;                Log.d(TAG, "onAnimationEnd");            }            @Override            public void onAnimationCancel(Animator animation) {                //onAnimationEnd(animation);                mExpandAndCollapseAnim = null;                Log.d(TAG, "onAnimationCancel");            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });        mExpandAndCollapseAnim.start();        return true;    }    public  int getHorizontalRange(   ) {        RecyclerView.ViewHolder viewHolder = mCallback.getChildViewHolder(mTargetView);        return mCallback.getHorizontalRange(viewHolder);    }    @Override    public boolean onDown(MotionEvent e) {        return false;    }    @Override    public void onShowPress(MotionEvent e) {    }    @Override    public boolean onSingleTapUp(MotionEvent e) {        return false;    }    @Override    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {        return false;    }    @Override    public void onLongPress(MotionEvent e) {    }    @Override    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {        if(Math.abs(velocityX) > mMinVelocity && Math.abs(velocityX) < mMaxVelocity) {            if(!smoothHorizontalExpandOrCollapse(velocityX) ) {                if(isCollapsed())                    mTargetView = null;                return true;            }        }        return false;    }    public interface Callback {        int getHorizontalRange(RecyclerView.ViewHolder holder);        RecyclerView.ViewHolder getChildViewHolder(View childView);        View findTargetView(float x, float y);    }}

ItemClickListener Item监听接口

package com.lw.widget.slideitem;import android.view.View;/** * Created by Administrator on 2016-07-05. */public interface ItemClickListener {    /**     * Item 普通点击     */    public void onItemClick(View view, int postion);}

3.在app目录下的build文件下添加如下代码:

dependencies {    compile fileTree(include: ['*.jar'], dir: 'libs')    testCompile 'junit:junit:4.12'    compile 'com.android.support:appcompat-v7:23.1.1'    compile 'com.android.support:recyclerview-v7:23.1.1'}

实现之后的效果图如下:

这里写图片描述

这里写图片描述

1 0
原创粉丝点击