仿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
- 仿QQ侧滑删除Item效果Demo
- 高仿 QQ 侧滑删除 Item 的效果
- 仿qq侧滑删除Item
- 仿QQ侧滑删除Item:Swipemenulistview的简单实现
- 仿QQ侧滑删除Item:Swipemenulistview的简单实现
- Android ListView侧滑item,仿QQ删除效果
- 仿QQ消息列表item横向滑动删除ListView中item侧滑删除
- 仿QQ列表左滑删除效果
- 仿QQ侧滑效果
- 仿QQ侧滑删除
- 仿qq侧滑删除
- Android Scroller详解,实现仿QQ列表item侧滑删除功能
- 仿QQ新版本侧滑效果
- 仿QQ侧滑效果,DragLayout使用方法
- 仿QQ侧滑效果(swifit)
- Android仿QQ侧滑效果
- 仿QQ侧滑菜单效果
- 仿QQ侧滑效果ViewDragHelper
- javascript写99乘法表
- selenium 和 phantomJS或chrome浏览器抓取渲染网页
- js报错总结
- [Unity3D]图形渲染优化、渲染管线优化、图形性能优化
- 判断是否连接网络以及是否是局域网
- 仿QQ侧滑删除Item效果Demo
- ubuntu桥接本机win7
- ES6: babel配置与babel-clic安装
- CentOS6.5上Boost库编译安装全记录
- clip和z-index的用法
- android 大图片压缩 及滑动不加载
- MFC 多线程编程总结
- 每日一linux命令(24)-------Linux 文件类型与扩展名
- 分析能力提高篇四:百度用户体验总监刘超下课,HR内部贴称其“给百度同学造成严重伤害”