博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ListView滑动删除
阅读量:6004 次
发布时间:2019-06-20

本文共 15307 字,大约阅读时间需要 51 分钟。

本来准备在ListView的每个Item的布局上设置一个隐藏的Button,当滑动的时候显示。但是因为每次只要存在一个Button,发现每个Item上的Button相互间不好控制。所以决定继承ListView然后结合PopupWindow。

首先是布局文件:

delete_btn.xml:这里只需要一个Button

1  
2
6
20
View Code

主布局文件:activity_main.xml,ListView的每个Item的样式直接使用了系统的android.R.layout.simple_list_item_1

1 
5 6
10
11 12
View Code

接下来看看QQListView的实现: 

1 package com.example.listviewitemslidedeletebtnshow;    2     3 import android.content.Context;    4 import android.util.AttributeSet;    5 import android.view.Gravity;    6 import android.view.LayoutInflater;    7 import android.view.MotionEvent;    8 import android.view.View;    9 import android.view.ViewConfiguration;   10 import android.widget.Button;   11 import android.widget.LinearLayout;   12 import android.widget.ListView;   13 import android.widget.PopupWindow;   14    15 public class QQListView extends ListView   16 {   17    18     private static final String TAG = "QQlistView";   19    20     // private static final int VELOCITY_SANP = 200;   21     // private VelocityTracker mVelocityTracker;   22     /**  23      * 用户滑动的最小距离  24      */   25     private int touchSlop;   26    27     /**  28      * 是否响应滑动  29      */   30     private boolean isSliding;   31    32     /**  33      * 手指按下时的x坐标  34      */   35     private int xDown;   36     /**  37      * 手指按下时的y坐标  38      */   39     private int yDown;   40     /**  41      * 手指移动时的x坐标  42      */   43     private int xMove;   44     /**  45      * 手指移动时的y坐标  46      */   47     private int yMove;   48    49     private LayoutInflater mInflater;   50    51     private PopupWindow mPopupWindow;   52     private int mPopupWindowHeight;   53     private int mPopupWindowWidth;   54    55     private Button mDelBtn;   56     /**  57      * 为删除按钮提供一个回调接口  58      */   59     private DelButtonClickListener mListener;   60    61     /**  62      * 当前手指触摸的View  63      */   64     private View mCurrentView;   65    66     /**  67      * 当前手指触摸的位置  68      */   69     private int mCurrentViewPos;   70    71     /**  72      * 必要的一些初始化  73      *   74      * @param context  75      * @param attrs  76      */   77     public QQListView(Context context, AttributeSet attrs)   78     {   79         super(context, attrs);   80    81         mInflater = LayoutInflater.from(context);   82         touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();   83    84         View view = mInflater.inflate(R.layout.delete_btn, null);   85         mDelBtn = (Button) view.findViewById(R.id.id_item_btn);   86         mPopupWindow = new PopupWindow(view, LinearLayout.LayoutParams.WRAP_CONTENT,   87                 LinearLayout.LayoutParams.WRAP_CONTENT);   88         /**  89          * 先调用下measure,否则拿不到宽和高  90          */   91         mPopupWindow.getContentView().measure(0, 0);   92         mPopupWindowHeight = mPopupWindow.getContentView().getMeasuredHeight();   93         mPopupWindowWidth = mPopupWindow.getContentView().getMeasuredWidth();   94     }   95    96     @Override   97     public boolean dispatchTouchEvent(MotionEvent ev)   98     {   99         int action = ev.getAction();  100         int x = (int) ev.getX();  101         int y = (int) ev.getY();  102         switch (action)  103         {  104   105         case MotionEvent.ACTION_DOWN:  106             xDown = x;  107             yDown = y;  108             /** 109              * 如果当前popupWindow显示,则直接隐藏,然后屏蔽ListView的touch事件的下传 110              */  111             if (mPopupWindow.isShowing())  112             {  113                 dismissPopWindow();  114                 return false;  115             }  116             // 获得当前手指按下时的item的位置  117             mCurrentViewPos = pointToPosition(xDown, yDown);  118             // 获得当前手指按下时的item  119             View view = getChildAt(mCurrentViewPos - getFirstVisiblePosition());  120             mCurrentView = view;  121             break;  122         case MotionEvent.ACTION_MOVE:  123             xMove = x;  124             yMove = y;  125             int dx = xMove - xDown;  126             int dy = yMove - yDown;  127             /** 128              * 判断是否是从右到左的滑动 129              */  130             if (xMove < xDown && Math.abs(dx) > touchSlop && Math.abs(dy) < touchSlop)  131             {  132                 // Log.e(TAG, "touchslop = " + touchSlop + " , dx = " + dx +  133                 // " , dy = " + dy);  134                 isSliding = true;  135             }  136             break;  137         }  138         return super.dispatchTouchEvent(ev);  139     }  140   141     @Override  142     public boolean onTouchEvent(MotionEvent ev)  143     {  144         int action = ev.getAction();  145         /** 146          * 如果是从右到左的滑动才相应 147          */  148         if (isSliding)  149         {  150             switch (action)  151             {  152             case MotionEvent.ACTION_MOVE:  153   154                 int[] location = new int[2];  155                 // 获得当前item的位置x与y  156                 mCurrentView.getLocationOnScreen(location);  157                 // 设置popupWindow的动画  158                 mPopupWindow.setAnimationStyle(R.style.popwindow_delete_btn_anim_style);  159                 mPopupWindow.update();  160                 mPopupWindow.showAtLocation(mCurrentView, Gravity.LEFT | Gravity.TOP,  161                         location[0] + mCurrentView.getWidth(), location[1] + mCurrentView.getHeight() / 2  162                                 - mPopupWindowHeight / 2);  163                 // 设置删除按钮的回调  164                 mDelBtn.setOnClickListener(new OnClickListener()  165                 {  166                     @Override  167                     public void onClick(View v)  168                     {  169                         if (mListener != null)  170                         {  171                             mListener.clickHappend(mCurrentViewPos);  172                             mPopupWindow.dismiss();  173                         }  174                     }  175                 });  176                 // Log.e(TAG, "mPopupWindow.getHeight()=" + mPopupWindowHeight);  177   178                 break;  179             case MotionEvent.ACTION_UP:  180                 isSliding = false;  181   182             }  183             // 相应滑动期间屏幕itemClick事件,避免发生冲突  184             return true;  185         }  186   187         return super.onTouchEvent(ev);  188     }  189   190     /** 191      * 隐藏popupWindow 192      */  193     private void dismissPopWindow()  194     {  195         if (mPopupWindow != null && mPopupWindow.isShowing())  196         {  197             mPopupWindow.dismiss();  198         }  199     }  200   201     public void setDelButtonClickListener(DelButtonClickListener listener)  202     {  203         mListener = listener;  204     }  205   206     interface DelButtonClickListener  207     {  208         public void clickHappend(int position);  209     }  210   211 }
View Code

 

代码注释写得很详细,简单说一下,在dispatchTouchEvent中设置当前是否响应用户滑动,然后在onTouchEvent中判断是否响应,如果响应则popupWindow以动画的形式展示出来。当然屏幕上如果存在PopupWindow则屏幕ListView的滚动与Item的点击,以及从右到左滑动时屏幕Item的click事件。

 

接下来是MainActivity.java,这里代码很简单不做介绍了。

1 package com.example.listviewitemslidedeletebtnshow;   2    3 import java.util.ArrayList;   4 import java.util.Arrays;   5 import java.util.List;   6    7 import android.app.Activity;   8 import android.os.Bundle;   9 import android.view.View;  10 import android.widget.AdapterView;  11 import android.widget.AdapterView.OnItemClickListener;  12 import android.widget.ArrayAdapter;  13 import android.widget.Toast;  14   15 import com.example.listviewitemslidedeletebtnshow.QQListView.DelButtonClickListener;  16   17 public class MainActivity extends Activity  18 {  19     private QQListView mListView;  20     private ArrayAdapter
mAdapter; 21 private List
mDatas; 22 23 @Override 24 protected void onCreate(Bundle savedInstanceState) 25 { 26 super.onCreate(savedInstanceState); 27 setContentView(R.layout.activity_main); 28 29 mListView = (QQListView) findViewById(R.id.id_listview); 30 // 不要直接Arrays.asList 31 mDatas = new ArrayList
(Arrays.asList("HelloWorld", "Welcome", "Java", "Android", "Servlet", "Struts", 32 "Hibernate", "Spring", "HTML5", "Javascript", "Lucene")); 33 mAdapter = new ArrayAdapter
(this, android.R.layout.simple_list_item_1, mDatas); 34 mListView.setAdapter(mAdapter); 35 36 mListView.setDelButtonClickListener(new DelButtonClickListener() 37 { 38 @Override 39 public void clickHappend(final int position) 40 { 41 Toast.makeText(MainActivity.this, position + " : " + mAdapter.getItem(position), 1).show(); 42 mAdapter.remove(mAdapter.getItem(position)); 43 } 44 }); 45 46 mListView.setOnItemClickListener(new OnItemClickListener() 47 { 48 @Override 49 public void onItemClick(AdapterView
parent, View view, int position, long id) 50 { 51 Toast.makeText(MainActivity.this, position + " : " + mAdapter.getItem(position), 1).show(); 52 } 53 }); 54 } 55 }
View Code

 

效果图如下:楼主使用asm.jar以及gifcamera截的gif,由于button的动画很短感觉截图效果很卡不流畅,大家有什么好的截图,还望推荐。有兴趣的还是下载源码看看效果i。

 

源码下载:http://download.csdn.net/detail/lmj623565791/7148325

 

上述文章实现的功能是:在ListView的Item上从右向左滑时,出现删除按钮,点击删除按钮把Item删除。

看过文章后,感觉没有必要把dispatchTouchEvent()和onTouchEvent()两个方法都重写,只要重写onTouchEvent就好了。于是对代码作了一些调整:

MyListView.java
1 public class MyListView extends ListView {  2     private static final String TAG = "MyListView";  3     private int mTouchSlop;  4     private int mXDown;  5     private int mYDown;  6     private int mCurrentPosition;  7     private View mCurrentView;  8     private PopupWindow mPopupWindow;  9     private LayoutInflater mInflater; 10     private boolean isSliding = false; 11     // 为删除按钮提供一个回调接口 12     private DelButtonClickListener mListener; 13     private Button mDelBtn; 14     private int mPopupWindowHeight; 15     private int mPopupWindowWidth; 16  17     public MyListView(Context context, AttributeSet attrs) { 18         super(context, attrs); 19         mInflater = LayoutInflater.from(context); 20         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 21  22         View view = mInflater.inflate(R.layout.delete_btn, null); 23         mDelBtn = (Button) view.findViewById(R.id.id_item_btn); 24         mPopupWindow = new PopupWindow(view, LinearLayout.LayoutParams.WRAP_CONTENT, 25                 LinearLayout.LayoutParams.WRAP_CONTENT); 26         // 如果需要通过点击PopupWindow之外的地方使其消失,则需要setFocusable(true). 27         mPopupWindow.setFocusable(true); 28         // Android 6.0以前的版本需要setBackgroundDrawable(), 29         // 才能实现通过点击PopupWindow之外的地方使其消失的功能。 30         mPopupWindow.setBackgroundDrawable(new ColorDrawable(0)); 31         // 先调用下measure,否则拿不到宽和高 32         mPopupWindow.getContentView().measure(0, 0); 33         mPopupWindowHeight = mPopupWindow.getContentView().getMeasuredHeight(); 34         mPopupWindowWidth = mPopupWindow.getContentView().getMeasuredWidth(); 35     } 36  37     @Override 38     public boolean onTouchEvent(MotionEvent ev) { 39         int action = ev.getAction(); 40         int x = (int) ev.getX(); 41         int y = (int) ev.getY(); 42  43         switch (action){ 44             case MotionEvent.ACTION_DOWN: 45                 isSliding = false; 46                 mXDown = x; 47                 mYDown = y; 48                 mCurrentPosition = pointToPosition(mXDown, mYDown); 49                 View view = getChildAt(mCurrentPosition - getFirstVisiblePosition()); 50                 mCurrentView = view; 51                 break; 52             case MotionEvent.ACTION_MOVE: 53                 int dx = x - mXDown; 54                 int dy = y - mYDown; 55  56                 Log.d(TAG, "mTouchSlop = " + mTouchSlop + ", dx = " + dx + ", dy = " + dy); 57  58                 if(mXDown > x && Math.abs(dx) > mTouchSlop && Math.abs(dy) < mTouchSlop){ 59                     Log.d(TAG, "isSliding"); 60                     isSliding = true; 61                     int[] location = new int[2]; 62                     mCurrentView.getLocationOnScreen(location); 63                     mPopupWindow.setAnimationStyle(R.style.popwindow_delete_btn_anim_style); 64                     mPopupWindow.update(); 65                     Log.d(TAG, "Height: " + mCurrentView.getHeight() + "," + mPopupWindow.getHeight()); 66                     mPopupWindow.showAtLocation(mCurrentView, Gravity.NO_GRAVITY, 67                             location[0] + mCurrentView.getWidth(), 68                             location[1] + mCurrentView.getHeight() / 2 - mPopupWindowHeight / 2); 69                     mDelBtn.setOnClickListener(new OnClickListener() { 70                         @Override 71                         public void onClick(View v) { 72                             mListener.clickHappend(mCurrentPosition); 73                             mPopupWindow.dismiss(); 74                         } 75                     }); 76                 } 77             case MotionEvent.ACTION_UP: 78                 // isSliding 如果这里恢复为false,则后面会执行super.onTouchEvent事件, 79                 // 而AbsListView的onTouchEvent调用了onTouchUp方法,在onTouchUp方法中有可能执行 80                 // performClick.run() --> performItemClick() --> super.performItemClick 81                 // --> mOnItemClickListener.onItemClick,这样最终触发Item的点击。 82                 // 因此此处依旧保持isSliding为true的状态,而在ACTION_DOWN事件中恢复isSliding为false, 83                 // 毕竟每个事件都以ACTION_DOWN开始。 84                 //isSliding = false; 85         } 86  87         if(isSliding){ 88             return true; 89         } 90  91         return super.onTouchEvent(ev); 92     } 93  94     public void setDelButtonClickListener(DelButtonClickListener listener){ 95         mListener = listener; 96     } 97  98     interface DelButtonClickListener{ 99         public void clickHappend(int position);100     }101 }102 103 MyListView.java

通过这个例子学习到:

1、ListView的Item点击事件的触发过程:

自定义ListView的onTouchEvent()  ---调用super.onTouchEvent()---> AbsListView.onTouchEvent() ---MotionEvent.ACTION_UP---> AbsListView.onTouchUp()

---(有可能)调用performClick.run()---> AbsListView.PerformClick.run() ---调用performItemClick()--->AbsListView.performItemClick()

---(有可能)调用super.performItemClick()---> AdapterView.performItemClick() ---mOnItemClickListener.onItemClick---> OnItemClickListener.onItemClick()

也就是Item的点击事件是在MotionEvent.ACTION_UP事件完成的,这样在自定义ListView的onTouchEvent()中,对MotionEvent.ACTION_UP直接return true消费掉事件,而不要调用super.onTouchEvent。这样就避免了删除按钮与Item点击事件的冲突。

 

2、PopupWindow--通过点击PopupWindow之外的地方使其消失

a、需要调用setFocusable()方法(PopupWindow中showAtLocation() --> createPopupLayoutParams() -->computeFlags() --> 设置FLAG_NOT_FOCUSABLE);

b、Android 6.0以前的版本需要setBackgroundDrawable()(具体原因见:)。

原文:http://blog.csdn.net/lmj623565791/article/details/22961279

   http://www.cnblogs.com/yarightok/p/5666127.html

 

转载于:https://www.cnblogs.com/Sharley/p/5666696.html

你可能感兴趣的文章
禁止Mysql默认端口访问Internet - MySQL - IT技术网
查看>>
基于用户投票的排名算法(二):Reddit
查看>>
下午最后的草坪
查看>>
Maven学习总结(七)——eclipse中使用Maven创建Web项目
查看>>
用PHP读取和编写XML DOM4
查看>>
1.部分(苹果)移动端的cookie不支持中文字符,2.从json字符串变为json对象时,只支持对象数组...
查看>>
vim配置及快捷键
查看>>
2018省赛赛第一次训练题解和ac代码
查看>>
[转载] win10进行端口转发
查看>>
利用JavaScript jQuery实现图片无限循环轮播(不借助于轮播插件)-----转载
查看>>
从零开始搭建vue项目 请求拦截器 响应拦截器
查看>>
HDU3257 Hello World!【打印图案+位运算】
查看>>
jquery 选择器
查看>>
The secret code
查看>>
Makefile 多目录自动编译
查看>>
学习笔记:Oracle dul数据挖掘 导出Oracle11G数据文件坏块中表中
查看>>
Linux 进程间通信(二) 管道
查看>>
深入浅出JQuery (二) 选择器
查看>>
CI框架 -- 驱动器
查看>>
FastMQ V0.2.0 stable版发布
查看>>