Android ScrollView反弹效果的实现

本文介绍如何在ScrollView中实现反弹效果,包括关键代码解析、实现步骤和使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自定义ScrollView控件:

[java]  view plain copy print ?
  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. }  


实现反弹效果:

[java]  view plain copy print ?
  1. <com.techrare.view.BounceScrollView  
  2.         android:layout_width="fill_parent"  
  3.         android:layout_height="fill_parent"  
  4.         android:background="@color/tab_chart_bg"  
  5.         android:scrollbars="none" >  
  6.   
  7.         <LinearLayout  
  8.             android:layout_width="fill_parent"  
  9.             android:layout_height="match_parent"  
  10.             android:gravity="center_horizontal"  
  11.             android:orientation="vertical"  
  12.             android:paddingLeft="20dp"  
  13.             android:paddingRight="20dp" >  
  14. <span style="white-space:pre">      </span><!-- 这里可以尽情的布局 -->  
  15.         </LinearLayout>  
  16. </com.techrare.view.BounceScrollView>  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值