Android自定义控件(二)——有弹性的ScrollView

本文在http://gundumw100.iteye.com/blog/1075286的基础上稍作修改

实现了当手指滑动到ScrollView的顶部、底部时,

可以继续的向上、向下拉伸。当释放手指的时候,向上、下弹回。

效果如图所示:

主要代码:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  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. }  
原文地址:https://www.cnblogs.com/Free-Thinker/p/4126083.html