标签:
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就不可以。
标签:
原文地址:http://www.cnblogs.com/royi123/p/4257788.html