ScrollView反弹效果

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

 

此View用于,在没有充满父级的时候,下拉会有反弹效果。但是Android自带的ScrollView就不可以。

 

posted on 2015-01-29 08:47  洛易  阅读(353)  评论(0编辑  收藏  举报