重要的话 开头说,not for the RecyclerView or ListView, for the Any ViewGroup.
本控件不依赖任何父布局,不是针对 RecyclerView、ListView,而是任意的ViewGroup里的childView都可以使用侧滑(删除)菜单。
最新使用说明:http://blog.csdn.net/zxt0601/article/details/53157090
Github传送门:https://github.com/mcxtzhang/SwipeDelMenuLayout
==================================================================================
【1 序言】
伸手党看完1 2 3 可直接去文末下载代码~
侧滑删除的轮子网上有很多,最初在github上看过一个,还是ListView时代,那是一个自定义ListView 实现侧滑删除的,当初就觉得这种做法不是最佳,万一我项目里又同时有自定义ListView的需求,会增加复杂度。
写这篇文章之前又通过毒度搜了一下,排名前几的CSDN文章,都是通过自定义ListVIew和ViewGropup实现的滑动删除。
况且现在是RecyclerView时代,难不成我要把那些代码再自定义RecyclerView写一遍么。
我想说No,网上大多数的做法代码侵入性太强,尽量不要继承 ListVIew 做什么事,换成 RecyclerView 呢,扩展性太局限了,
本文的做法只要在 Item 的根布局换成这个 自定义ViewGroup 即可,完全不 care 你用 RecyclerView 还是 ListVIew,耦合性为 0
听说隔壁IOS 侧滑删除是一个系统自带的控件,那么我们Android党能否也自定义一个ViewGroup控件,然后一劳永逸,每次简单拿来用就好了呢?
自定义ViewGroup实现侧滑删除简单,难得是还要同时 处理多指滑动的屏蔽,防止两个侧滑菜单同时出现,等等,
有办法将这些东西都用一个ViewGroup搞定么?
看本文如何巧用static类变量来解决这些矛盾冲突。
==================================================================================
【2 预览】
那么我们先看一下最终的效果:
非阻塞式Android特色版本(我司自用版本 ) 平滑滚动动画用属性动画实现 ,即使有一个侧滑菜单处于打开状态,在打开其他item侧滑菜单时,依然无阻塞,会自动关闭上次开启的菜单:~
为了满足个别产品的,高仿IOS版本 平滑滚动用Scroller实现 阻塞式交互(自己的说法) 打开了某个侧滑菜单后 点击其他地方会自动关闭这个侧滑菜单 并且不能做其他操作 :
包含且不仅包含以下功能:
1 侧滑拉出菜单。
2 点击除了这个item的其他位置,菜单关闭。
3 侧滑过程中,不许父控件上下滑动。
4 多指同时滑动,屏蔽后触摸的几根手指。
5 不会同时展开两个侧滑菜单。
6 侧滑菜单时 拦截了长按事件。
7 侧滑时,拦截了点击事件(20160905更新)
8 通过开关 isLeftSwipe支持左滑右滑(2016 09 30 更新):
==================================================================================
【3 使用预览】
看起来还不错吧,忽略颜值,可以再细调,主要的是解决了那几个难题,那么,使用起来麻烦么。
就这么简单,<mcxtzhang.listswipemenudemo.view.CstSwipeDelMenuViewGroup xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true"> <TextView android:id="@+id/content" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:text="试试看" /> <Button android:id="@+id/btnDelete" android:layout_width="60dp" android:layout_height="match_parent" android:background="@color/red_ff4a57" android:text="删除" /> </mcxtzhang.listswipemenudemo.view.CstSwipeDelMenuViewGroup>
只需要在 侧滑删除的item的layout的xml里,将根布局父控件换成我们的自定义ViewGroup即可。
第一个子View放置item的内容即可(正式项目里一般是一个ViewGroup),
从2+子View开始,是我们的侧滑菜单区域,如我们的demo图,是三个Button。
//注意事项,设置item点击,不能对整个holder.itemView设置咯,只能对第一个子View,即原来的content设置,这算是局限性吧。 (holder.content).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(mContext, ""+mDatas.get(position).name, Toast.LENGTH_SHORT).show(); } });
==================================================================================
【4 实现方法】
使用起来这么简单,让我们一步一步实现它吧。
首先说的是,颜值非本文的重点,UI动画仍有调整空间,重要的是在一个自定义ViewGroup里处理那些冲突。
首先,本类继承自ViewGroup,那么onMeasure()和onLayout()方法,就需要我们自己动手写了,而且在上文我们也提到,使用时,第一个子View放置item内容,2+子View为侧滑菜单区域,那么这需要我们在onMeasure()和onLayout()方法里进行一些特殊处理,设置第一个childView宽度为全屏。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //Log.d(TAG, "onMeasure() called with: " + "widthMeasureSpec = [" + widthMeasureSpec + "], heightMeasureSpec = [" + heightMeasureSpec + "]"); super.onMeasure(widthMeasureSpec, heightMeasureSpec); mRightMenuWidths = 0;//由于ViewHolder的复用机制,每次这里要手动恢复初始值 int childCount = getChildCount(); //add by 2016 08 11 为了子View的高,可以matchParent(参考的FrameLayout 和LinearLayout的Horizontal) final boolean measureMatchParentChildren = MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY; boolean isNeedMeasureChildHeight = false; for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); if (childView.getVisibility() != GONE) { //measureChild(childView, widthMeasureSpec, heightMeasureSpec); measureChildWithMargins(childView, widthMeasureSpec, 0, heightMeasureSpec, 0); final MarginLayoutParams lp = (MarginLayoutParams) childView.getLayoutParams(); mHeight = Math.max(mHeight, childView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); if (measureMatchParentChildren && lp.height == LayoutParams.MATCH_PA