所谓阻尼效果,什么是阻尼效果,好吧,我不知道怎么去描述它,看图吧,真相一看就懂(参看附件gif图) 

 

自定义阻尼效果listview_listView 阻尼效果 自定义lis

此效果在iphone上非常常见,当列表滑动到顶部或者底部,没有内容时,列表跟随手指移动一定距离,android自身的listview是滑动到顶部或者底部时,会有一层淡淡的颜色,个人比较喜欢后者,但常常在项目中会有类似于前者的需求。仿爱疯,你懂的。

好了,这里我们在说一下可能需要主要到的地方:

1.手指滑动,listview中的item跟随手指滚动(如何做到?)

2.item移动的距离小于手指滑动的距离(这个好办)

3.手指抬起之后,listview自动滚回到顶部位置(怎么办呢?)

这里我还是在代码里面来说吧:

activity_main.xml

 

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  2.     xmlns:tools="http://schemas.android.com/tools" 
  3.     android:layout_width="match_parent" 
  4.     android:layout_height="match_parent" > 
  5.  
  6.     <TextView 
  7.         android:layout_width="wrap_content" 
  8.         android:layout_height="wrap_content" 
  9.         android:layout_centerHorizontal="true" 
  10.         android:padding="@dimen/padding_medium" 
  11.         android:text="listview阻尼效果" 
  12.         android:id="@+id/textview" 
  13.         android:textSize="18sp" 
  14.         tools:context=".MainActivity" /> 
  15.  
  16.     <com.example.pulllistview.PullListView 
  17.         android:id="@+id/list" 
  18.         android:layout_width="fill_parent" 
  19.         android:layout_marginTop="10dp" 
  20.         android:layout_below="@+id/textview" 
  21.         android:layout_height="wrap_content" /> 
  22.  
  23.  <!--    <com.example.pulllistview.BounceListView 
  24.         android:id="@+id/list" 
  25.         android:layout_width="fill_parent" 
  26.         android:layout_marginTop="10dp" 
  27.         android:layout_below="@+id/textview" 
  28.         android:layout_height="wrap_content" /> --> 
  29.  
  30. </RelativeLayout> 

PullListView.java

 

  1. package com.example.pulllistview; 
  2.  
  3.  
  4.  
  5. import android.content.Context; 
  6. import android.util.AttributeSet; 
  7. import android.util.Log; 
  8. import android.view.MotionEvent; 
  9. import android.widget.ListView; 
  10.  
  11. /**自定义阻尼效果列表**/ 
  12. public class PullListView extends ListView implements Runnable { 
  13.     private float mLastDownY = 0f;  
  14.     private int mDistance = 0;  
  15.     private int mStep = 0;  
  16.     private boolean mPositive = false;  
  17.     private String Tag="PullListview"
  18.   
  19.  
  20.     public PullListView (Context context, AttributeSet attrs) {  
  21.           super(context, attrs);  
  22.     }  
  23.   
  24.     public PullListView (Context context, AttributeSet attrs, int defStyle) {  
  25.           super(context, attrs, defStyle);  
  26.     }  
  27.   
  28.     public PullListView (Context context) {  
  29.           super(context);  
  30.     }  
  31.   
  32.     @Override  
  33.     public boolean onTouchEvent(MotionEvent event) {  
  34.          switch (event.getAction()) {  
  35.               case MotionEvent.ACTION_DOWN: //手指按下时触发 
  36.                   Log.d(Tag,"ActionDown"); 
  37.                    if (mLastDownY == 0f && mDistance == 0) {                        
  38.                          mLastDownY = event.getY();  
  39.                          Log.d(Tag,"mLastDownY赋值"+mLastDownY); 
  40.                    return true;  
  41.               }  
  42.               break;  
  43.   
  44.     case MotionEvent.ACTION_CANCEL:  
  45.            break; 
  46.  
  47.     case MotionEvent.ACTION_UP: //手指抬起之后触发 
  48.       Log.d(Tag,"ActionUP"); 
  49.           if (mDistance != 0) {  
  50.               System.out.println("---post"); 
  51.            mStep = 1;  
  52.            mPositive = (mDistance >= 0);  
  53.            this.post(this);          
  54.            return true;  
  55.         }  
  56.         mLastDownY = 0f;  
  57.         mDistance = 0;  
  58.         break;  
  59.   
  60.     case MotionEvent.ACTION_MOVE:  //手指按下之后滑动触发
  61.       Log.d(Tag,"ActionMove"); 
  62.         if (mLastDownY != 0f) {               
  63.               mDistance = (int) (mLastDownY - event.getY());  
  64.               Log.d(Tag,"mLastDownY不为0,view跟随滑动"+"mDistance"+mDistance); 
  65.               if ((mDistance < 0 && getFirstVisiblePosition() == 0 && 
  66. getChildAt(0).getTop() == 0) || (mDistance > 0 &&
  67.  getLastVisiblePosition() == getCount() - 1)) {  
  68.                   //第一个位置并且是想下拉,就滑动或者最后一个位置向上拉  
  69.                   //这个判断的作用是在非顶端的部分不会有此滚动 
  70.                   mDistance /= 2; //这里是为了减少滚动的距离 
  71.                    scrollTo(0, mDistance); //滚动 
  72.                    return true;  
  73.                }  
  74.         }  
  75.         mDistance = 0;  
  76.         break;  
  77.         }  
  78.         return super.onTouchEvent(event);  
  79.     }  
  80.   
  81.     public void run() {  
  82.            Log.d(Tag,"ActionUP调用post"); 
  83.           mDistance += mDistance > 0 ? -mStep : mStep;  
  84.           scrollTo(0, mDistance);  
  85.           if ((mPositive && mDistance <= 0) || (!mPositive && mDistance >= 0)) {  
  86.                 scrollTo(0, 0);  
  87.                 mDistance = 0;  
  88.                 mLastDownY = 0f;  
  89.                 Log.d(Tag,"post中置0"); 
  90.                 return;  
  91.            }  
  92.           mStep += 1;  
  93.         // this.postDelayed(this, 10);  
  94.           this.post(this); 
  95.      }  
  96. }  

MainActivtiy.java

 

  1. package com.example.pulllistview; 
  2.  
  3. import java.util.ArrayList; 
  4. import java.util.List; 
  5.  
  6. import android.app.Activity; 
  7. import android.os.Bundle; 
  8. import android.view.Menu; 
  9. import android.widget.ArrayAdapter; 
  10.  
  11. public class MainActivity extends Activity { 
  12.  
  13.     @Override 
  14.     public void onCreate(Bundle savedInstanceState) { 
  15.          super.onCreate(savedInstanceState); 
  16.          setContentView(R.layout.activity_main); 
  17.          PullListView listview = (PullListView)findViewById(R.id.list); 
  18.          listview.setAdapter(new ArrayAdapter<String>(this,
  19. android.R.layout.simple_list_item_checked,getData())); 
  20.      
  21.     } 
  22. private List<String> getData(){ 
  23.          
  24.         List<String> data = new ArrayList<String>(); 
  25.         data.add("阻尼效果测试数据1"); 
  26.         data.add("阻尼效果测试数据2"); 
  27.         data.add("阻尼效果测试数据3"); 
  28.         data.add("阻尼效果测试数据4"); 
  29.         data.add("阻尼效果测试数据5"); 
  30.         data.add("阻尼效果测试数据6"); 
  31.         data.add("阻尼效果测试数据7"); 
  32.         data.add("阻尼效果测试数据8"); 
  33.         data.add("阻尼效果测试数据9"); 
  34.         data.add("阻尼效果测试数据10"); 
  35.         data.add("阻尼效果测试数据11"); 
  36.         data.add("阻尼效果测试数据12"); 
  37.         data.add("阻尼效果测试数据13"); 
  38.         return data; 
  39.     } 
  40.  
  41.     @Override 
  42.     public boolean onCreateOptionsMenu(Menu menu) { 
  43.         getMenuInflater().inflate(R.menu.activity_main, menu); 
  44.         return true; 
  45.     } 
  46.  
  47.      

 此处再提供另一种方法,但需要leve 为2.3及之后的才能使用,原因之前的sdk尚未此方法。该方法非常简单,还是看源码先.

BounceListView.java

 

  1. package com.example.pulllistview; 
  2.  
  3. import android.content.Context; 
  4. import android.util.AttributeSet; 
  5. import android.util.DisplayMetrics; 
  6. import android.widget.ListView; 
  7.  
  8. public class BounceListView extends ListView{ 
  9.     private static final int MAX_Y_OVERSCROLL_DISTANCE = 200
  10.      
  11.     private Context mContext; 
  12.     private int mMaxYOverscrollDistance; 
  13.      
  14.     public BounceListView(Context context){ 
  15.         super(context); 
  16.         mContext = context
  17.         initBounceListView(); 
  18.     } 
  19.      
  20.     public BounceListView(Context context, AttributeSet attrs){ 
  21.         super(context, attrs); 
  22.         mContext = context
  23.         initBounceListView(); 
  24.     } 
  25.      
  26.     public BounceListView(Context context, AttributeSet attrs, int defStyle){ 
  27.         super(context, attrs, defStyle); 
  28.         mContext = context
  29.         initBounceListView(); 
  30.     } 
  31.      
  32.     private void initBounceListView(){ 
  33.         //get the density of the screen and do some maths with it on the max overscroll
  34. distance variable so that you get similar behaviors no matter what the screen size 
  35.          
  36.         final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); 
  37.             final float density = metrics.density; 
  38.          
  39.         mMaxYOverscrollDistance = (int) (density * MAX_Y_OVERSCROLL_DISTANCE); 
  40.     } 
  41.      //主要就是这个方法了,直接重载复写就好
  42.     @Override 
  43.     protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, 
  44. int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, 
  45. boolean isTouchEvent){  
  46.         //This is where the magic happens, we have replaced the incoming 
  47. maxOverScrollY with our own custom variable mMaxYOverscrollDistance;  
  48.         return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, 
  49. scrollRangeY, maxOverScrollX, mMaxYOverscrollDistance, isTouchEvent);   
  50.     } 
  51.