首页 > 代码库 > 【转】Android自定义控件(三)——有弹性的ListView

【转】Android自定义控件(三)——有弹性的ListView

上一次我们试验了有弹性的ScrollView。详情

这一次,我们来试验有弹性的ScrollView。

国际惯例,效果图:



主要代码:

  

  1 import android.content.Context;  2 import android.graphics.Rect;  3 import android.util.AttributeSet;  4 import android.view.MotionEvent;  5 import android.view.animation.Animation;  6 import android.view.animation.Animation.AnimationListener;  7 import android.view.animation.TranslateAnimation;  8 import android.widget.AbsListView;  9 import android.widget.ListView; 10  11 /** 12  * ElasticScrollView有弹性的ListView 13  */ 14 public class ElasticListView extends ListView { 15     private float y; 16     private Rect normal = new Rect(); 17     private boolean animationFinish = true; 18  19     public ElasticListView(Context context) { 20         super(context); 21         init(); 22     } 23  24     public ElasticListView(Context context, AttributeSet attrs) { 25         super(context, attrs); 26         init(); 27     } 28  29     protected void onScrollChanged(int l, int t, int oldl, int oldt) { 30  31     } 32  33     boolean overScrolled = false; 34     private void init() { 35         setOnScrollListener(new OnScrollListener() { 36             @Override 37             public void onScrollStateChanged(AbsListView view, int scrollState) { 38             } 39  40             @Override 41             public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 42                 overScrolled = false; 43             } 44         }); 45     } 46      47     @Override 48     protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { 49         overScrolled = true; 50     } 51  52     @Override 53     public boolean onTouchEvent(MotionEvent ev) { 54         commOnTouchEvent(ev); 55         return super.onTouchEvent(ev); 56     } 57  58     public void commOnTouchEvent(MotionEvent ev) { 59         if (animationFinish) { 60             int action = ev.getAction(); 61             switch (action) { 62             case MotionEvent.ACTION_DOWN: 63                 y = ev.getY(); 64                 break; 65             case MotionEvent.ACTION_UP: 66                 y = 0; 67                 if (isNeedAnimation()) { 68                     animation(); 69                 } 70                 break; 71             case MotionEvent.ACTION_MOVE: 72                 final float preY = y == 0 ? ev.getY() : y; 73                 float nowY = ev.getY(); 74                 int deltaY = (int) (preY - nowY); 75  76                 y = nowY; 77                 // 当滚动到最上或者最下时就不会再滚动,这时移动布局 78                 if (isNeedMove(deltaY)) { 79                     if (normal.isEmpty()) { 80                         // 保存正常的布局位置 81                         normal.set(getLeft(), getTop(), getRight(), getBottom()); 82                     } 83                     // 移动布局 84                     layout(getLeft(), getTop() - deltaY / 2, getRight(), getBottom() - deltaY / 2); 85                 } 86                 break; 87             default: 88                 break; 89             } 90         } 91     } 92  93     // 开启动画移动 94     public void animation() { 95         // 开启移动动画 96         TranslateAnimation ta = new TranslateAnimation(0, 0, 0, normal.top - getTop()); 97         ta.setDuration(200); 98         ta.setAnimationListener(new AnimationListener() { 99             @Override100             public void onAnimationStart(Animation animation) {101                 animationFinish = false;102 103             }104 105             @Override106             public void onAnimationRepeat(Animation animation) {107 108             }109 110             @Override111             public void onAnimationEnd(Animation animation) {112                 clearAnimation();113                 // 设置回到正常的布局位置114                 layout(normal.left, normal.top, normal.right, normal.bottom);115                 normal.setEmpty();116                 animationFinish = true;117             }118         });119         startAnimation(ta);120     }121 122     // 是否需要开启动画123     public boolean isNeedAnimation() {124         return !normal.isEmpty();125     }126 127     // 是否需要移动布局128     public boolean isNeedMove(float deltaY) {129         if (overScrolled && getChildCount() > 0) {130             if (getLastVisiblePosition() == getCount() - 1 && deltaY > 0) {131                 return true;132             }133             if (getFirstVisiblePosition() == 0 && deltaY < 0) {134                 return true;135             }136         }137         return false;138     }139 }

 

测试代码:

 1 public class MainActivity extends Activity { 2     ElasticListView listView; 3     @Override 4     protected void onCreate(Bundle savedInstanceState) { 5         super.onCreate(savedInstanceState); 6         setContentView(R.layout.activity_main); 7          8         listView = (ElasticListView) findViewById(R.id.listview); 9         10         String[] listValues = new String[20];11         for (int i=0;i<listValues.length;i++) {12             listValues[i] = "TextView" + i;13         }14         listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listValues));15     }16 }

 

 1 public class MainActivity extends Activity { 2     ElasticListView listView; 3     @Override 4     protected void onCreate(Bundle savedInstanceState) { 5         super.onCreate(savedInstanceState); 6         setContentView(R.layout.activity_main); 7          8         listView = (ElasticListView) findViewById(R.id.listview); 9         10         String[] listValues = new String[20];11         for (int i=0;i<listValues.length;i++) {12             listValues[i] = "TextView" + i;13         }14         listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listValues));15     }16 }

 

【转】Android自定义控件(三)——有弹性的ListView