ListView侧滑删除的实现,SlideDeleteListView,针对ScrollView嵌套ListView视图和手势冲突优化
来源:互联网 发布:java界面设计 编辑:程序博客网 时间:2024/03/28 21:20
转载:http://blog.csdn.net/ausboyue/article/details/52565237的博客
关于ListView侧滑删除这是个老话题,大多数APP都具有这样类似的功能,对于一位Android初涉者来说,实现这样的功能确实有一点难度,网上的实现方法也层出不穷,我仔细在网上翻了一下,居然看到了还有很多实现侧滑的第三方依赖包,觉得有些无语,尝试使用一番,大多数实现还是很好的,比我今天要说的好的多,当然也有劣质的包,这里也就不多说了。既然是老话题,那么没有一点实现上的优势,我也说不下去,这个优势大概就是只要自定义一个ListView便可以实现侧滑删除功能,尤其是对ScrollView嵌套ListView视图和手势冲突的优化。严格意义上这个实现方式也是我以前在网上看到的,后来基于这个实现思想修改优化的。好了,开教程:
1.先假设一个ListView的Item子布局message_item.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="62dp"
- android:background="@drawable/common_list_item_bg"
- android:gravity="center_vertical"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:orientation="horizontal">
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <ImageView
- android:id="@+id/iv_icon_read_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginLeft="15dp"
- android:src="@drawable/ic_msg_unread" />
-
- <TextView
- android:id="@+id/tv_msg_content"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginLeft="15dp"
- android:layout_toRightOf="@id/iv_icon_read_status"
- android:text="订单预定成功;订单号6607967"
- android:textColor="@color/common_text"
- android:textSize="14sp" />
-
-
- <TextView
- android:id="@+id/tv_msg_time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:layout_marginRight="15dp"
- android:text="前天 13:21"
- android:textColor="@color/text_smoke"
- android:textSize="12sp" />
- </RelativeLayout>
-
- <TextView
- android:id="@+id/tv_btn_delete"
- android:layout_width="70dp"
- android:layout_height="match_parent"
- android:background="@color/red"
- android:clickable="true"
- android:gravity="center"
- android:text="删除"
- android:textColor="@color/white"
- android:textSize="17sp" />
- </LinearLayout>
前面的RelativeLayout里的内容就是大家常见的ListView的Item视图,后面的TextView就是我们主角删除按钮,这里把它也作为Item的子布局内容了。从布局里可以看出,删除按钮TextView已经被RelativeLayout挤到最右边,而不在屏幕显示区域内。此时该Item的长度实际长度是屏幕的长度+删除的按钮的长度(这里是70dp)。
2.下面我们自定义ListView----->SlideDeleteListView 这里注意一点,就是尽量不要在任何自定义View中传入某布局,那么以后修改或用于别的项目,其要求发生了一些变化,还要针对被改变的布局修改逻辑代码,这是我个人的一种开发思想,大家听听就好了。
-
-
-
-
-
-
-
- public SlideDeleteListView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
-
- WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-
- DisplayMetrics metrics = new DisplayMetrics();
-
- wm.getDefaultDisplay().getMetrics(metrics);
-
- mSreeenWidth = metrics.widthPixels;
- }
SlideDeleteListView构造方法中获取屏幕宽度mSreeenWidth
-
-
-
-
-
-
- @SuppressLint("ClickableViewAccessibility")
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- onActionDowm(ev);
- break;
- case MotionEvent.ACTION_MOVE:
- return onActionMove(ev);
- case MotionEvent.ACTION_UP:
- onActionUp(ev);
- break;
- }
- return super.onTouchEvent(ev);
- }
重写SlideDeleteListView手势事件
-
-
-
- private void onActionDowm(MotionEvent e) {
- if (isBtnDelShow) {
- resetItemView();
- }
- mDownX = (int) e.getX();
- mDownY = (int) e.getY();
-
- Integer currentPosition = pointToPosition(mDownX, mDownY);
- if (-1 == currentPosition) {
- return;
- }
- itemViewGroup = (ViewGroup) getChildAt(currentPosition - getFirstVisiblePosition());
-
- mBtnDelWidth = itemViewGroup.getChildAt(1).getLayoutParams().width;
-
- params = (LinearLayout.LayoutParams) itemViewGroup.getChildAt(0).getLayoutParams();
- params.width = mSreeenWidth;
- itemViewGroup.getChildAt(0).setLayoutParams(params);
- }
手指按下的时候,把刚才那个item常见显示的视图RelativeLayout宽度成屏幕的宽度,以及获得删除按钮TextView 的宽度,isBtnDelShow为flag,用于标记删除是否处于显示状态,若显示,点击时重置下Item显示状态(即不显示删除按钮的视图状态),Integer currentPosition = pointToPosition(mDownX, mDownY),currentPosition 为-1时表示手指点击点是在item之间的分割线上,不作逻辑处理。itemViewGroup即Item的布局,itemViewGroup.getChildAt(0)为Item子View,即上述的RelativeLayout。
-
-
-
- private boolean onActionMove(MotionEvent e) {
- int nowX = (int) e.getX();
- int nowY = (int) e.getY();
-
- if (Math.abs(nowX - mDownX) > Math.abs(nowY - mDownY)) {
-
- requestDisallowInterceptTouchEvent(true);
-
- if (nowX < mDownX) {
- int srollX = mDownX - nowX;
-
- if (srollX >= mBtnDelWidth) {
- srollX = mBtnDelWidth;
- }
- params.leftMargin = -srollX;
- itemViewGroup.getChildAt(0).setLayoutParams(params);
- }
-
- return true;
- }
- return super.onTouchEvent(e);
- }
这里的思路就是判定左滑时,并根据左滑的绝对距离(即手指向左边滑动的实际水平距离),实时设定RelativeLayout视图的MarginLeft为相应距离的负值以达到感觉item布局像是被手指划走的效果,删除按钮也随即从左边逐渐显示出来。注意下requestDisallowInterceptTouchEvent(true)这行代码的注释,手指点击的位置是在ListView上,且是左右滑,为了避免手势冲突,不让父View即ScrollView拦截该手势事件。
手指释放时判断向左滑动的距离,做显示按钮或重置最初的Item显示状态逻辑。-
-
-
- private void onActionUp(MotionEvent e) {
-
- if (-params.leftMargin >= mBtnDelWidth / 2) {
- params.leftMargin = -mBtnDelWidth;
- isBtnDelShow = true;
- } else {
-
- resetItemView();
- }
- itemViewGroup.getChildAt(0).setLayoutParams(params);
- }
-
-
-
-
-
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-
- Object object = getParent().getParent();
- if (object instanceof ScrollView) {
-
- int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
- super.onMeasure(widthMeasureSpec, expandSpec);
- } else {
-
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
- }
-
-
-
- public void resetItemView() {
- params.leftMargin = 0;
- itemViewGroup.getChildAt(0).setLayoutParams(params);
- isBtnDelShow = false;
- }
看注释。
3.在适配器Adapter中获取该ListView对象,当删除按钮显示时,点击删除,删除集合里对应的数据,ListView对象再调用上述的resetItemView()方法,再调用adapter的notifyDataSetChanged()方法更新界面。
- holder.tv_btn_delete.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- items.remove(items.get(position));
- lv_messages.resetItemView();
- notifyDataSetChanged();
- }
- });
效果图:
Demo源码下载
0 0