time 
设为首页】【收藏本站
当前位置: 主页 > 电脑网络 > 操作系统 > 嵌入式 > Android > Android下使用Scroller实现绚丽的ListView左右滑动删除Item效果

Android下使用Scroller实现绚丽的ListView左右滑动删除Item效果

时间:2014-01-26 11:19 点击:2597次 字体:[ ]




 

我在上一篇文章中从源码的角度介绍了Scroller的滚动实现原理介绍了Scroller的滚动实现原理,相信大家对Scroller的使用有一定的了解,这篇文章就给大家带来使用Scroller的小例子,来帮助大家更加熟悉的掌握Scroller的使用,掌握好了Scroller的使用我们就能实现很多滑动的效果。例如侧滑菜单,launcher,ListView的下拉刷新等等效果,我今天实现的是ListView的item的左右滑动删除item的效果,现在很多朋友看到这个效果应该是在Android的通知栏下拉中看到这个滑动删除的效果吧,我看到这个效果是在我之前的三星手机上左右滑动打电话发短信的效果,感觉很棒,不过现在很多手机联系人滑动都不是我之前那台手机的效果啦,网上很多朋友也写了关于滑动删除ListView的item的例子,有些是滑动手指离开之后然后给item加向左或者向右的移动动画,我觉得这样子的用户体验不是很好,所以今天自己也写了一个关于ListView左右滑动删除Item的小例子,ListView的item会随着手指在屏幕上的滑动而滑动,手指离开屏幕的时候item会根据判断向左或者向右划出屏幕,就是跟通知栏的效果差不多,接下来就带大家来实现这个效果。
先说下实现该效果的主要思路
先根据手指触摸的点来获取点击的是ListView的哪一个item
手指在屏幕中滑动我们利用scrollBy()来使该item跟随手指一起滑动
手指放开的时候,我们判断手指拖动的距离来判断item到底是滑出屏幕还是回到开始位置
主要思路就是上面这三步,接下来我们就用代码来实现吧,首先我们新建一个项目,叫SlideCutListView
根据需求我们需要自己自定义一个ListView来实现该功能,接下来先贴出代码再讲解具体的实现

  1. package com.example.slidecutlistview; 
  2.  
  3. import android.content.Context; 
  4. import android.util.AttributeSet; 
  5. import android.view.MotionEvent; 
  6. import android.view.VelocityTracker; 
  7. import android.view.View; 
  8. import android.view.ViewConfiguration; 
  9. import android.view.WindowManager; 
  10. import android.widget.AdapterView; 
  11. import android.widget.ListView; 
  12. import android.widget.Scroller; 
  13.  
  14. /** 
  15.  * @blog http://blog.csdn.net/xiaanming 
  16.  *  
  17.  * @author xiaanming 
  18.  *  
  19.  */ 
  20. public class SlideCutListView extends ListView { 
  21.     /** 
  22.      * 当前滑动的ListView position 
  23.      */ 
  24.     private int slidePosition; 
  25.     /** 
  26.      * 手指按下X的坐标 
  27.      */ 
  28.     private int downY; 
  29.     /** 
  30.      * 手指按下Y的坐标 
  31.      */ 
  32.     private int downX; 
  33.     /** 
  34.      * 屏幕宽度 
  35.      */ 
  36.     private int screenWidth; 
  37.     /** 
  38.      * ListView的item 
  39.      */ 
  40.     private View itemView; 
  41.     /** 
  42.      * 滑动类 
  43.      */ 
  44.     private Scroller scroller; 
  45.     private static final int SNAP_VELOCITY = 600
  46.     /** 
  47.      * 速度追踪对象 
  48.      */ 
  49.     private VelocityTracker velocityTracker; 
  50.     /** 
  51.      * 是否响应滑动,默认为不响应 
  52.      */ 
  53.     private boolean isSlide = false
  54.     /** 
  55.      * 认为是用户滑动的最小距离 
  56.      */ 
  57.     private int mTouchSlop; 
  58.     /** 
  59.      *  移除item后的回调接口 
  60.      */ 
  61.     private RemoveListener mRemoveListener; 
  62.     /** 
  63.      * 用来指示item滑出屏幕的方向,向左或者向右,用一个枚举值来标记 
  64.      */ 
  65.     private RemoveDirection removeDirection; 
  66.  
  67.     // 滑动删除方向的枚举值 
  68.     public enum RemoveDirection { 
  69.         RIGHT, LEFT; 
  70.     } 
  71.  
  72.  
  73.     public SlideCutListView(Context context) { 
  74.         this(context, null); 
  75.     } 
  76.  
  77.     public SlideCutListView(Context context, AttributeSet attrs) { 
  78.         this(context, attrs, 0); 
  79.     } 
  80.  
  81.     public SlideCutListView(Context context, AttributeSet attrs, int defStyle) { 
  82.         super(context, attrs, defStyle); 
  83.         screenWidth = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth(); 
  84.         scroller = new Scroller(context); 
  85.         mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); 
  86.     } 
  87.      
  88.     /** 
  89.      * 设置滑动删除的回调接口 
  90.      * @param removeListener 
  91.      */ 
  92.     public void setRemoveListener(RemoveListener removeListener) { 
  93.         this.mRemoveListener = removeListener; 
  94.     } 
  95.  
  96.     /** 
  97.      * 分发事件,主要做的是判断点击的是那个item, 以及通过postDelayed来设置响应左右滑动事件 
  98.      */ 
  99.     @Override 
  100.     public boolean dispatchTouchEvent(MotionEvent event) { 
  101.         switch (event.getAction()) { 
  102.         case MotionEvent.ACTION_DOWN: { 
  103.             addVelocityTracker(event); 
  104.  
  105.             // 假如scroller滚动还没有结束,我们直接返回 
  106.             if (!scroller.isFinished()) { 
  107.                 return super.dispatchTouchEvent(event); 
  108.             } 
  109.             downX = (int) event.getX(); 
  110.             downY = (int) event.getY(); 
  111.  
  112.             slidePosition = pointToPosition(downX, downY); 
  113.  
  114.             // 无效的position, 不做任何处理 
  115.             if (slidePosition == AdapterView.INVALID_POSITION) { 
  116.                 return super.dispatchTouchEvent(event); 
  117.             } 
  118.  
  119.             // 获取我们点击的item view 
  120.             itemView = getChildAt(slidePosition - getFirstVisiblePosition()); 
  121.             break
  122.         } 
  123.         case MotionEvent.ACTION_MOVE: { 
  124.             if (Math.abs(getScrollVelocity()) > SNAP_VELOCITY 
  125.                     || (Math.abs(event.getX() - downX) > mTouchSlop && Math 
  126.                             .abs(event.getY() - downY) < mTouchSlop)) { 
  127.                 isSlide = true
  128.                  
  129.             } 
  130.             break
  131.         } 
  132.         case MotionEvent.ACTION_UP: 
  133.             recycleVelocityTracker(); 
  134.             break
  135.         } 
  136.  
  137.         return super.dispatchTouchEvent(event); 
  138.     } 
  139.  
  140.     /** 
  141.      * 往右滑动,getScrollX()返回的是左边缘的距离,就是以View左边缘为原点到开始滑动的距离,所以向右边滑动为负值 
  142.      */ 
  143.     private void scrollRight() { 
  144.         removeDirection = RemoveDirection.RIGHT; 
  145.         final int delta = (screenWidth + itemView.getScrollX()); 
  146.         // 调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item 
  147.         scroller.startScroll(itemView.getScrollX(), 0, -delta, 0
  148.                 Math.abs(delta)); 
  149.         postInvalidate(); // 刷新itemView 
  150.     } 
  151.  
  152.     /** 
  153.      * 向左滑动,根据上面我们知道向左滑动为正值 
  154.      */ 
  155.     private void scrollLeft() { 
  156.         removeDirection = RemoveDirection.LEFT; 
  157.         final int delta = (screenWidth - itemView.getScrollX()); 
  158.         // 调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item 
  159.         scroller.startScroll(itemView.getScrollX(), 0, delta, 0
  160.                 Math.abs(delta)); 
  161.         postInvalidate(); // 刷新itemView 
  162.     } 
  163.  
  164.     /** 
  165.      * 根据手指滚动itemView的距离来判断是滚动到开始位置还是向左或者向右滚动 
  166.      */ 
  167.     private void scrollByDistanceX() { 
  168.         // 如果向左滚动的距离大于屏幕的二分之一,就让其删除 
  169.         if (itemView.getScrollX() >= screenWidth / 2) { 
  170.             scrollLeft(); 
  171.         } else if (itemView.getScrollX() <= -screenWidth / 2) { 
  172.             scrollRight(); 
  173.         } else { 
  174.             // 滚回到原始位置,为了偷下懒这里是直接调用scrollTo滚动 
  175.             itemView.scrollTo(00); 
  176.         } 
  177.  
  178.     } 
  179.  
  180.     /** 
  181.      * 处理我们拖动ListView item的逻辑 
  182.      */ 
  183.     @Override 
  184.     public boolean onTouchEvent(MotionEvent ev) { 
  185.         if (isSlide && slidePosition != AdapterView.INVALID_POSITION) { 
  186.             requestDisallowInterceptTouchEvent(true); 
  187.             addVelocityTracker(ev); 
  188.             final int action = ev.getAction(); 
  189.             int x = (int) ev.getX(); 
  190.             switch (action) { 
  191.             case MotionEvent.ACTION_DOWN: 
  192.                 break
  193.             case MotionEvent.ACTION_MOVE: 
  194.                  
  195.                 MotionEvent cancelEvent = MotionEvent.obtain(ev); 
  196.                 cancelEvent.setAction(MotionEvent.ACTION_CANCEL | 
  197.                            (ev.getActionIndex()<< MotionEvent.ACTION_POINTER_INDEX_SHIFT)); 
  198.                 onTouchEvent(cancelEvent); 
  199.                  
  200.                 int deltaX = downX - x; 
  201.                 downX = x; 
  202.  
  203.                 // 手指拖动itemView滚动, deltaX大于0向左滚动,小于0向右滚 
  204.                 itemView.scrollBy(deltaX, 0); 
  205.                  
  206.                 return true;  //拖动的时候ListView不滚动 
  207.             case MotionEvent.ACTION_UP: 
  208.                 int velocityX = getScrollVelocity(); 
  209.                 if (velocityX > SNAP_VELOCITY) { 
  210.                     scrollRight(); 
  211.                 } else if (velocityX < -SNAP_VELOCITY) { 
  212.                     scrollLeft(); 
  213.                 } else { 
  214.                     scrollByDistanceX(); 
  215.                 } 
  216.                  
  217.                 recycleVelocityTracker(); 
  218.                 // 手指离开的时候就不响应左右滚动 
  219.                 isSlide = false
  220.                 break
  221.             } 
  222.         } 
  223.  
  224.         //否则直接交给ListView来处理onTouchEvent事件 
  225.         return super.onTouchEvent(ev); 
  226.     } 
  227.  
  228.     @Override 
  229.     public void computeScroll() { 
  230.         // 调用startScroll的时候scroller.computeScrollOffset()返回true, 
  231.         if (scroller.computeScrollOffset()) { 
  232.             // 让ListView item根据当前的滚动偏移量进行滚动 
  233.             itemView.scrollTo(scroller.getCurrX(), scroller.getCurrY()); 
  234.              
  235.             postInvalidate(); 
  236.  
  237.             // 滚动动画结束的时候调用回调接口 
  238.             if (scroller.isFinished()) { 
  239.                 if (mRemoveListener == null) { 
  240.                     throw new NullPointerException("RemoveListener is null, we should called setRemoveListener()"); 
  241.                 } 
  242.                  
  243.                 itemView.scrollTo(00); 
  244.                 mRemoveListener.removeItem(removeDirection, slidePosition); 
  245.             } 
  246.         } 
  247.     } 
  248.  
  249.     /** 
  250.      * 添加用户的速度跟踪器 
  251.      *  
  252.      * @param event 
  253.      */ 
  254.     private void addVelocityTracker(MotionEvent event) { 
  255.         if (velocityTracker == null) { 
  256.             velocityTracker = VelocityTracker.obtain(); 
  257.         } 
  258.  
  259.         velocityTracker.addMovement(event); 
  260.     } 
  261.  
  262.     /** 
  263.      * 移除用户速度跟踪器 
  264.      */ 
  265.     private void recycleVelocityTracker() { 
  266.         if (velocityTracker != null) { 
  267.             velocityTracker.recycle(); 
  268.             velocityTracker = null
  269.         } 
  270.     } 
  271.  
  272.     /** 
  273.      * 获取X方向的滑动速度,大于0向右滑动,反之向左 
  274.      *  
  275.      * @return 
  276.      */ 
  277.     private int getScrollVelocity() { 
  278.         velocityTracker.computeCurrentVelocity(1000); 
  279.         int velocity = (int) velocityTracker.getXVelocity(); 
  280.         return velocity; 
  281.     } 
  282.  
  283.     /** 
  284.      *  
  285.      * 当ListView item滑出屏幕,回调这个接口 
  286.      * 我们需要在回调方法removeItem()中移除该Item,然后刷新ListView 
  287.      *  
  288.      * @author xiaanming 
  289.      * 
  290.      */ 
  291.     public interface RemoveListener { 
  292.         public void removeItem(RemoveDirection direction, int position); 
  293.     } 
  294.  

首先我们重写dispatchTouchEvent()方法,该方法是事件的分发方法,我们在里面只做了一些简单的步骤,我们按下屏幕的时候,如果某个item正在进行滚动,我们直接交给SlideCutListView的父类处理分发事件,否则根据点击的X,Y坐标利用pointToPosition(int x, int y)来获取点击的是ListView的哪一个position,从而获取到我们需要滑动的item的View,我们还在该方法加入了滑动速度的检测,并且在ACTION_MOVE的时候来判断是否响应item的左右移动,用isSlide来记录是否响应左右滑动
然后就是重写onTouchEvent()方法,我们先判断isSlide为true,并且我们点击的是ListView上面的有效的position,否则直接交给SlideCutListView的父类也就是ListView来处理,在ACTION_MOVE中调用scrollBy()来移动item,scrollBy()是相对item的上一个位置进行移动的,所以我们每次都要用现在移动的距离减去上一个位置的距离然后赋给scrollBy()方法,这样子我们就实现了item的平滑移动,当我们将手指抬起的时候,我们先根据手指滑动的速度来确定是item是滑出屏幕还是滑动至原始位置,如果向右的速度大于我们设置的SNAP_VELOCITY,item就调用scrollRight()方法滚出屏幕,如果向左的速度小于-SNAP_VELOCITY,则调用scrollLeft()向左滚出屏幕,如果我们是缓慢的移动item,则调用scrollByDistanceX()方法来判断是滚到那个位置
在scrollRight()和scrollLeft()方法中我们使用Scroller类的startScroll()方法先设置滚动的参数,然后调用postInvalidate()来刷新界面,界面刷新就会调用computeScroll()方法,我们在里面处理滚动逻辑就行了,值得一提的是computeScroll()里面的这段代码

  1. itemView.scrollTo(00); 

 



本文地址 : http://www.fengfly.com/plus/view-214542-1.html
标签: Android ListView scroller
------分隔线----------------------------
最新评论 查看所有评论
发表评论 查看所有评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
验证码: