【转】Android自定义控件(二)——有弹性的ScrollView
原文地址:http://blog.csdn.net/a105865708/article/details/17784041
实现了当手指滑动到ScrollView的顶部、底部时,
可以继续的向上、向下拉伸。当释放手指的时候,向上、下弹回。
效果如图所示:
主要代码:
1 public class ElasticScrollView extends ScrollView { 2 private View inner; 3 private float y; 4 private Rect normal = new Rect(); 5 private boolean animationFinish = true; 6 7 public ElasticScrollView(Context context) { 8 super(context); 9 } 10 11 public ElasticScrollView(Context context, AttributeSet attrs) { 12 super(context, attrs); 13 } 14 15 @Override 16 protected void onFinishInflate() { 17 if (getChildCount() > 0) { 18 inner = getChildAt(0); 19 } 20 } 21 22 @Override 23 public boolean onInterceptTouchEvent(MotionEvent ev) { 24 return super.onInterceptTouchEvent(ev); 25 } 26 27 @Override 28 public boolean onTouchEvent(MotionEvent ev) { 29 if (inner == null) { 30 return super.onTouchEvent(ev); 31 } else { 32 commOnTouchEvent(ev); 33 } 34 return super.onTouchEvent(ev); 35 } 36 37 public void commOnTouchEvent(MotionEvent ev) { 38 if (animationFinish) { 39 int action = ev.getAction(); 40 switch (action) { 41 case MotionEvent.ACTION_DOWN: 42 // System.out.println("ACTION_DOWN"); 43 y = ev.getY(); 44 super.onTouchEvent(ev); 45 break; 46 case MotionEvent.ACTION_UP: 47 // System.out.println("ACTION_UP"); 48 y = 0; 49 if (isNeedAnimation()) { 50 animation(); 51 } 52 super.onTouchEvent(ev); 53 break; 54 case MotionEvent.ACTION_MOVE: 55 // System.out.println("ACTION_MOVE"); 56 final float preY = y == 0 ? ev.getY() : y; 57 float nowY = ev.getY(); 58 int deltaY = (int) (preY - nowY); 59 // 滚动 60 // scrollBy(0, deltaY); 61 62 y = nowY; 63 // 当滚动到最上或者最下时就不会再滚动,这时移动布局 64 if (isNeedMove()) { 65 if (normal.isEmpty()) { 66 // 保存正常的布局位置 67 normal.set(inner.getLeft(), inner.getTop(), inner.getRight(), inner.getBottom()); 68 } 69 // 移动布局 70 inner.layout(inner.getLeft(), inner.getTop() - deltaY / 2, inner.getRight(), inner.getBottom() - deltaY / 2); 71 } else { 72 super.onTouchEvent(ev); 73 } 74 break; 75 default: 76 break; 77 } 78 } 79 } 80 81 // 开启动画移动 82 83 public void animation() { 84 // 开启移动动画 85 TranslateAnimation ta = new TranslateAnimation(0, 0, 0, normal.top - inner.getTop()); 86 ta.setDuration(200); 87 ta.setAnimationListener(new AnimationListener() { 88 @Override 89 public void onAnimationStart(Animation animation) { 90 animationFinish = false; 91 92 } 93 94 @Override 95 public void onAnimationRepeat(Animation animation) { 96 97 } 98 99 @Override 100 public void onAnimationEnd(Animation animation) { 101 inner.clearAnimation(); 102 // 设置回到正常的布局位置 103 inner.layout(normal.left, normal.top, normal.right, normal.bottom); 104 normal.setEmpty(); 105 animationFinish = true; 106 } 107 }); 108 inner.startAnimation(ta); 109 } 110 111 // 是否需要开启动画 112 public boolean isNeedAnimation() { 113 return !normal.isEmpty(); 114 } 115 116 // 是否需要移动布局 117 public boolean isNeedMove() { 118 int offset = inner.getMeasuredHeight() - getHeight(); 119 int scrollY = getScrollY(); 120 if (scrollY == 0 || scrollY == offset) { 121 return true; 122 } 123 return false; 124 } 125 126 }