Android ScrollView反弹效果的实现

来源:互联网 发布:百度网站怎么优化排名 编辑:程序博客网 时间:2024/06/03 01:22
  1. /** 
  2.  * ScrollView反弹效果的实现 
  3.  */  
  4. public class BounceScrollView extends ScrollView {  
  5.     private View inner;// 孩子View  
  6.   
  7.     private float y;// 点击时y坐标  
  8.   
  9.     private Rect normal = new Rect();// 矩形(这里只是个形式,只是用于判断是否需要动画.)  
  10.   
  11.     private boolean isCount = false;// 是否开始计算  
  12.   
  13.     public BounceScrollView(Context context, AttributeSet attrs) {  
  14.         super(context, attrs);  
  15.     }  
  16.   
  17.     /*** 
  18.      * 根据 XML 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onFinishInflate 
  19.      * 方法,也应该调用父类的方法,使该方法得以执行. 
  20.      */  
  21.     @Override  
  22.     protected void onFinishInflate() {  
  23.         if (getChildCount() > 0) {  
  24.             inner = getChildAt(0);  
  25.         }  
  26.     }  
  27.   
  28.     /*** 
  29.      * 监听touch 
  30.      */  
  31.     @Override  
  32.     public boolean onTouchEvent(MotionEvent ev) {  
  33.         if (inner != null) {  
  34.             commOnTouchEvent(ev);  
  35.         }  
  36.   
  37.         return super.onTouchEvent(ev);  
  38.     }  
  39.   
  40.     /*** 
  41.      * 触摸事件 
  42.      *  
  43.      * @param ev 
  44.      */  
  45.     public void commOnTouchEvent(MotionEvent ev) {  
  46.         int action = ev.getAction();  
  47.         switch (action) {  
  48.         case MotionEvent.ACTION_DOWN:  
  49.             break;  
  50.         case MotionEvent.ACTION_UP:  
  51.             // 手指松开.  
  52.             if (isNeedAnimation()) {  
  53.                 animation();  
  54.                 isCount = false;  
  55.             }  
  56.             break;  
  57.         /*** 
  58.          * 排除出第一次移动计算,因为第一次无法得知y坐标, 在MotionEvent.ACTION_DOWN中获取不到, 
  59.          * 因为此时是MyScrollView的touch事件传递到到了LIstView的孩子item上面.所以从第二次计算开始. 
  60.          * 然而我们也要进行初始化,就是第一次移动的时候让滑动距离归0. 之后记录准确了就正常执行. 
  61.          */  
  62.         case MotionEvent.ACTION_MOVE:  
  63.             final float preY = y;// 按下时的y坐标  
  64.             float nowY = ev.getY();// 时时y坐标  
  65.             int deltaY = (int) (preY - nowY);// 滑动距离  
  66.             if (!isCount) {  
  67.                 deltaY = 0// 在这里要归0.  
  68.             }  
  69.   
  70.             y = nowY;  
  71.             // 当滚动到最上或者最下时就不会再滚动,这时移动布局  
  72.             if (isNeedMove()) {  
  73.                 // 初始化头部矩形  
  74.                 if (normal.isEmpty()) {  
  75.                     // 保存正常的布局位置  
  76.                     normal.set(inner.getLeft(), inner.getTop(),  
  77.                             inner.getRight(), inner.getBottom());  
  78.                 }  
  79.                 Log.e("jj""矩形:" + inner.getLeft() + "," + inner.getTop()  
  80.                         + "," + inner.getRight() + "," + inner.getBottom());  
  81.                 // 移动布局  
  82.                 inner.layout(inner.getLeft(), inner.getTop() - deltaY / 2,  
  83.                         inner.getRight(), inner.getBottom() - deltaY / 2);  
  84.             }  
  85.             isCount = true;  
  86.             break;  
  87.   
  88.         default:  
  89.             break;  
  90.         }  
  91.     }  
  92.   
  93.     /*** 
  94.      * 回缩动画 
  95.      */  
  96.     public void animation() {  
  97.         // 开启移动动画  
  98.         TranslateAnimation ta = new TranslateAnimation(00, inner.getTop(),  
  99.                 normal.top);  
  100.         ta.setDuration(200);  
  101.         inner.startAnimation(ta);  
  102.         // 设置回到正常的布局位置  
  103.         inner.layout(normal.left, normal.top, normal.right, normal.bottom);  
  104.   
  105.         Log.e("jj""回归:" + normal.left + "," + normal.top + "," + normal.right  
  106.                 + "," + normal.bottom);  
  107.   
  108.         normal.setEmpty();  
  109.   
  110.     }  
  111.   
  112.     // 是否需要开启动画  
  113.     public boolean isNeedAnimation() {  
  114.         return !normal.isEmpty();  
  115.     }  
  116.   
  117.     /*** 
  118.      * 是否需要移动布局 inner.getMeasuredHeight():获取的是控件的总高度 
  119.      *  
  120.      * getHeight():获取的是屏幕的高度 
  121.      *  
  122.      * @return 
  123.      */  
  124.     public boolean isNeedMove() {  
  125.         int offset = inner.getMeasuredHeight() - getHeight();  
  126.         int scrollY = getScrollY();  
  127.         Log.e("jj""scrolly=" + scrollY);  
  128.         // 0是顶部,后面那个是底部  
  129.         if (scrollY == 0 || scrollY == offset) {  
  130.             return true;  
  131.         }  
  132.         return false;  
  133.     }  
  134.   
  135. }  
1 0
原创粉丝点击