有弹性的ScrollView&ListView&HorizontalScrollView

原帖: 

http://dev.10086.cn/cmdn/bbs/thread-40685-1-1.html 

Java代码   收藏代码
  1. import android.content.Context;  
  2. import android.graphics.Rect;  
  3. import android.util.AttributeSet;  
  4. import android.view.MotionEvent;  
  5. import android.view.View;  
  6. import android.view.animation.TranslateAnimation;  
  7. import android.widget.ScrollView;  
  8.   
  9. /** 
  10.  * ElasticScrollView有弹性的ScrollView 
  11.  */  
  12. public class ElasticScrollView extends ScrollView {  
  13.     private View inner;  
  14.     private float y;  
  15.     private Rect normal = new Rect();;  
  16.   
  17.     public ElasticScrollView(Context context) {  
  18.         super(context);  
  19.     }  
  20.       
  21.     public ElasticScrollView(Context context, AttributeSet attrs) {  
  22.         super(context, attrs);  
  23.     }  
  24.   
  25.     @Override  
  26.     protected void onFinishInflate() {  
  27.         if (getChildCount() > 0) {  
  28.             inner = getChildAt(0);  
  29.         }  
  30.     }  
  31.   
  32.     @Override  
  33.     public boolean onTouchEvent(MotionEvent ev) {  
  34.         if (inner == null) {  
  35.             return super.onTouchEvent(ev);  
  36.         } else {  
  37.             commOnTouchEvent(ev);  
  38.         }  
  39.         return super.onTouchEvent(ev);  
  40.     }  
  41.   
  42.     public void commOnTouchEvent(MotionEvent ev) {  
  43.         int action = ev.getAction();  
  44.         switch (action) {  
  45.         case MotionEvent.ACTION_DOWN:  
  46.             y = ev.getY();  
  47.             break;  
  48.         case MotionEvent.ACTION_UP:  
  49.             if (isNeedAnimation()) {  
  50.                 animation();  
  51.             }  
  52.             break;  
  53.         case MotionEvent.ACTION_MOVE:  
  54.             final float preY = y;  
  55.             float nowY = ev.getY();  
  56.             int deltaY = (int) (preY - nowY);  
  57.             // 滚动  
  58.             scrollBy(0, deltaY);  
  59.   
  60.             y = nowY;  
  61.             // 当滚动到最上或者最下时就不会再滚动,这时移动布局  
  62.             if (isNeedMove()) {  
  63.                 if (normal.isEmpty()) {  
  64.                     // 保存正常的布局位置  
  65.                     normal.set(inner.getLeft(), inner.getTop(), inner  
  66.                             .getRight(), inner.getBottom());  
  67.   
  68.                 }  
  69.                 // 移动布局  
  70.                 inner.layout(inner.getLeft(), inner.getTop() - deltaY, inner  
  71.                         .getRight(), inner.getBottom() - deltaY);  
  72.             }  
  73.             break;  
  74.         default:  
  75.             break;  
  76.         }  
  77.     }  
  78.   
  79.     // 开启动画移动  
  80.   
  81.     public void animation() {  
  82.         // 开启移动动画  
  83.         TranslateAnimation ta = new TranslateAnimation(00, inner.getTop(),  
  84.                 normal.top);  
  85.         ta.setDuration(200);  
  86.         inner.startAnimation(ta);  
  87.         // 设置回到正常的布局位置  
  88.         inner.layout(normal.left, normal.top, normal.right, normal.bottom);  
  89.         normal.setEmpty();  
  90.     }  
  91.   
  92.     // 是否需要开启动画  
  93.     public boolean isNeedAnimation() {  
  94.         return !normal.isEmpty();  
  95.     }  
  96.   
  97.     // 是否需要移动布局  
  98.     public boolean isNeedMove() {  
  99.         int offset = inner.getMeasuredHeight() - getHeight();  
  100.         int scrollY = getScrollY();  
  101.         if (scrollY == 0 || scrollY == offset) {  
  102.             return true;  
  103.         }  
  104.         return false;  
  105.     }  
  106.   
  107. }  


Java代码   收藏代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <com.rebound.myscroll.ElasticScrollView  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:orientation="vertical"   
  5.     android:layout_width="fill_parent"  
  6.     android:id="@+id/sv"   
  7.     android:layout_height="fill_parent"  
  8.     >  
  9.     <TextView android:id="@+id/tv"   
  10.         android:layout_width="fill_parent"  
  11.         android:layout_height="wrap_content"  
  12.           android:text="......一个很长很长的字符串......"  
  13.   
  14.  />  
  15. </com.rebound.myscroll.ElasticScrollView>  


或者另一种实现方式(推荐)  
Java代码   收藏代码
  1. import android.content.Context;  
  2. import android.util.AttributeSet;  
  3. import android.util.DisplayMetrics;  
  4. import android.widget.ScrollView;  
  5.   
  6. public class MtScrollView extends ScrollView {  
  7. private static final int MAX_Y_OVERSCROLL_DISTANCE = 200;   
  8.       
  9.     private Context mContext;   
  10.     private int mMaxYOverscrollDistance;   
  11.         
  12.     public MtScrollView(Context context){   
  13.         super(context);   
  14.         mContext = context;   
  15.         initBounceListView();   
  16.     }   
  17.         
  18.     public MtScrollView(Context context, AttributeSet attrs){   
  19.         super(context, attrs);   
  20.         mContext = context;   
  21.         initBounceListView();  
  22.     }   
  23.         
  24.     public MtScrollView(Context context, AttributeSet attrs, int defStyle){   
  25.         super(context, attrs, defStyle);   
  26.         mContext = context;   
  27.         initBounceListView();   
  28.     }   
  29.         
  30.     private void initBounceListView(){   
  31.         final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();   
  32.             final float density = metrics.density;   
  33.             
  34.         mMaxYOverscrollDistance = (int) (density * MAX_Y_OVERSCROLL_DISTANCE);   
  35.     }   
  36.     @Override  
  37.     protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent){    
  38.         //这块是关键性代码  
  39.         return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mMaxYOverscrollDistance, isTouchEvent);     
  40.     }  
  41. }  



通过上面的方法,也可以实现有弹性的ListView:
 
Java代码   收藏代码
  1. public class BounceListView extends ListView  
  2. {  
  3.     private static final int MAX_Y_OVERSCROLL_DISTANCE = 200;  
  4.       
  5.     private Context mContext;  
  6.     private int mMaxYOverscrollDistance;  
  7.       
  8.     public BounceListView(Context context)   
  9.     {  
  10.         super(context);  
  11.         mContext = context;  
  12.         initBounceListView();  
  13.     }  
  14.       
  15.     public BounceListView(Context context, AttributeSet attrs)   
  16.     {  
  17.         super(context, attrs);  
  18.         mContext = context;  
  19.         initBounceListView();  
  20.     }  
  21.       
  22.     public BounceListView(Context context, AttributeSet attrs, int defStyle)   
  23.     {  
  24.         super(context, attrs, defStyle);  
  25.         mContext = context;  
  26.         initBounceListView();  
  27.     }  
  28.       
  29.     private void initBounceListView()  
  30.     {  
  31.         //get the density of the screen and do some maths with it on the max overscroll distance  
  32.         //variable so that you get similar behaviors no matter what the screen size  
  33.           
  34.         final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();  
  35.             final float density = metrics.density;  
  36.           
  37.         mMaxYOverscrollDistance = (int) (density * MAX_Y_OVERSCROLL_DISTANCE);  
  38.     }  
  39.       
  40.     @Override  
  41.     protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent)   
  42.     {   
  43.         //This is where the magic happens, we have replaced the incoming maxOverScrollY with our own custom variable mMaxYOverscrollDistance;   
  44.         return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mMaxYOverscrollDistance, isTouchEvent);    
  45.     }  
  46.       
  47. }  


左右滑动加弹性的HorizontalScrollView  
Java代码   收藏代码
  1. import android.content.Context;  
  2. import android.graphics.Rect;  
  3. import android.util.AttributeSet;  
  4. import android.view.MotionEvent;  
  5. import android.view.View;  
  6. import android.view.animation.TranslateAnimation;  
  7. import android.widget.HorizontalScrollView;  
  8.   
  9. public class ElasticHorizontalScrollView extends HorizontalScrollView {  
  10.     private View inner;  
  11.     private Rect normal = new Rect();  
  12.     private float x;  
  13.   
  14.     public ElasticHorizontalScrollView(Context context, AttributeSet attrs) {  
  15.         super(context, attrs);  
  16.     }  
  17.   
  18.     public ElasticHorizontalScrollView(Context context) {  
  19.         super(context);  
  20.     }  
  21.   
  22.     @Override  
  23.     protected void onFinishInflate() {  
  24.         if (getChildCount() > 0) {  
  25.             inner = getChildAt(0);  
  26.         }  
  27.         super.onFinishInflate();  
  28.     }  
  29.   
  30.     @Override  
  31.     public boolean onTouchEvent(MotionEvent ev) {  
  32.         if (ev == null) {  
  33.             return super.onTouchEvent(ev);  
  34.         } else {  
  35.             commOnTouchEvent(ev);  
  36.         }  
  37.         return super.onTouchEvent(ev);  
  38.     }  
  39.   
  40.     private void commOnTouchEvent(MotionEvent ev) {  
  41.         int action = ev.getAction();  
  42.         switch (action) {  
  43.         case MotionEvent.ACTION_DOWN:  
  44.             x = ev.getX();  
  45.             break;  
  46.         case MotionEvent.ACTION_UP:  
  47.             if (isNeedAnimation()) {  
  48.                 animation();  
  49.             }  
  50.             break;  
  51.         case MotionEvent.ACTION_MOVE:  
  52.             final float preX = x;  
  53.             float nowX = ev.getX();  
  54.             int distanceX = (int) (preX - nowX);  
  55.             scrollBy(distanceX, 0);  
  56.             x = nowX;  
  57.             if (isNeedMove()) {  
  58.                 if (normal.isEmpty()) {  
  59.                     normal.set(inner.getLeft(), inner.getTop(), inner.getRight(), inner.getBottom());  
  60.                 }  
  61.                 inner.layout(inner.getLeft() - distanceX, inner.getTop(), inner.getRight() - distanceX, inner.getBottom());  
  62.             }  
  63.   
  64.             break;  
  65.   
  66.         default:  
  67.             break;  
  68.         }  
  69.     }  
  70.   
  71.     private void animation() {  
  72.         TranslateAnimation mTranslateAnimation = new TranslateAnimation(inner.getLeft(), 0, normal.left, 0);  
  73.         mTranslateAnimation.setDuration(50);  
  74.         inner.setAnimation(mTranslateAnimation);  
  75.         inner.layout(normal.left, normal.top, normal.right, normal.bottom);  
  76.         normal.setEmpty();  
  77.   
  78.     }  
  79.   
  80.     private boolean isNeedAnimation() {  
  81.         return !normal.isEmpty();  
  82.     }  
  83.   
  84.     private boolean isNeedMove() {  
  85.         int offset = inner.getMeasuredWidth() - getWidth();  
  86.         int scrollX = getScrollX();  
  87.         if (scrollX == 0 || offset == scrollX)  
  88.             return true;  
  89.         return false;  
  90.     }  
  91. }  

Xml代码   收藏代码
  1. <com.example.horiztalscrollviewtext.ElasticHorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="match_parent"  
  4.     android:background="#D1EEEE"  
  5.     android:scrollbars="none" >  
  6.   
  7.     <LinearLayout  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="fill_parent"  
  10.         android:background="#F5F5F5"  
  11.         android:orientation="horizontal" >  
  12.   
  13.         <ImageView  
  14.             android:layout_width="fill_parent"  
  15.             android:layout_height="fill_parent"  
  16.             android:src="@drawable/main_guide_0" />  
  17.   
  18.         <ImageView  
  19.             android:layout_width="fill_parent"  
  20.             android:layout_height="fill_parent"  
  21.             android:src="@drawable/main_guide_0" />  
  22.   
  23.         <ImageView  
  24.             android:layout_width="fill_parent"  
  25.             android:layout_height="fill_parent"  
  26.             android:src="@drawable/main_guide_0" />  
  27.     </LinearLayout>  
  28.   
  29. </com.example.horiztalscrollviewtext.ElasticHorizontalScrollView>  


也可以这样实现有弹性的HorizontalScrollView: (推荐)  
Java代码   收藏代码
  1. import android.content.Context;  
  2. import android.util.AttributeSet;  
  3. import android.util.DisplayMetrics;  
  4. import android.widget.HorizontalScrollView;  
  5.   
  6. public class BouncyHScrollView extends HorizontalScrollView {  
  7.   
  8.     private static final int MAX_X_OVERSCROLL_DISTANCE = 200;     
  9.     private Context mContext;     
  10.     private int mMaxXOverscrollDistance;  
  11.       
  12.     public BouncyHScrollView(Context context) {  
  13.         super(context);  
  14.         // TODO Auto-generated constructor stub  
  15.         mContext = context;     
  16.         initBounceDistance();  
  17.     }  
  18.     public BouncyHScrollView(Context context, AttributeSet attrs) {  
  19.         super(context, attrs);  
  20.         // TODO Auto-generated constructor stub  
  21.         mContext = context;     
  22.         initBounceDistance();  
  23.     }  
  24.     public BouncyHScrollView(Context context, AttributeSet attrs, int defStyle) {  
  25.         super(context, attrs, defStyle);  
  26.         // TODO Auto-generated constructor stub  
  27.         mContext = context;     
  28.         initBounceDistance();  
  29.     }  
  30.       
  31.     private void initBounceDistance(){     
  32.         final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();     
  33.         mMaxXOverscrollDistance = (int) (metrics.density * MAX_X_OVERSCROLL_DISTANCE);     
  34.     }     
  35.       
  36.     @Override    
  37.     protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent){      
  38.         //这块是关键性代码    
  39.         return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, mMaxXOverscrollDistance, maxOverScrollY, isTouchEvent);       
  40.     }    
  41.   
  42. }  


另付: 
自定义ScrollView,以解决viewflipper 与scrollview的手势冲突 
Java代码   收藏代码
  1. import android.content.Context;  
  2. import android.util.AttributeSet;  
  3. import android.view.GestureDetector;  
  4. import android.view.MotionEvent;  
  5. import android.widget.ScrollView;  
  6.   
  7. /** 
  8. * 自定义ScrollView,并重写其onTouchEvent和dispatchTouchEvent方法, 
  9. * 以解决viewflipper 与scrollview的手势冲突 
  10. * @author yangjiantong 
  11. * 
  12. */  
  13. public class MyScrollView extends ScrollView {  
  14.   
  15.         GestureDetector gestureDetector;  
  16.         public MyScrollView(Context context) {  
  17.                 super(context);  
  18.                 // TODO Auto-generated constructor stub  
  19.         }  
  20.   
  21.         public MyScrollView(Context context, AttributeSet attrs) {  
  22.                 super(context, attrs);  
  23.                 // TODO Auto-generated constructor stub  
  24.         }  
  25.   
  26.         public MyScrollView(Context context, AttributeSet attrs, int defStyle) {  
  27.                 super(context, attrs, defStyle);  
  28.                 // TODO Auto-generated constructor stub  
  29.         }  
  30.   
  31.         public void setGestureDetector(GestureDetector gestureDetector) {  
  32.                 this.gestureDetector = gestureDetector;  
  33.         }  
  34.   
  35.         @Override  
  36.         public boolean onTouchEvent(MotionEvent ev) {  
  37.                 // TODO Auto-generated method stub  
  38.                 super.onTouchEvent(ev);  
  39.                 return gestureDetector.onTouchEvent(ev);  
  40.         }  
  41.   
  42.         @Override  
  43.         public boolean dispatchTouchEvent(MotionEvent ev){  
  44.                 gestureDetector.onTouchEvent(ev);  
  45.                 super.dispatchTouchEvent(ev);  
  46.                 return true;  
  47.         }   
  48.           
  49. }  


如何解决ViewPager在ScrollView中滑动经常失效、无法正常滑动问题?(推荐) 
解决方法只需要在接近水平滚动时ScrollView不处理事件而交由其子View(即这里的ViewPager)处理即可,重写ScrollView的onInterceptTouchEvent函数,如下: 
Java代码   收藏代码
  1. package cc.newnews.view;  
  2.   
  3. import android.content.Context;  
  4. import android.util.AttributeSet;  
  5. import android.view.GestureDetector;  
  6. import android.view.GestureDetector.SimpleOnGestureListener;  
  7. import android.view.MotionEvent;  
  8. import android.widget.ScrollView;  
  9.   
  10. public class VerticalScrollView extends ScrollView {  
  11.   
  12.     private GestureDetector mGestureDetector;  
  13.   
  14.     public VerticalScrollView(Context context, AttributeSet attrs) {  
  15.         super(context, attrs);  
  16.         mGestureDetector = new GestureDetector(context, new YScrollDetector());  
  17.     }  
  18.   
  19.     @Override  
  20.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  21.         return super.onInterceptTouchEvent(ev)  
  22.                 && mGestureDetector.onTouchEvent(ev);  
  23.     }  
  24.   
  25.     class YScrollDetector extends SimpleOnGestureListener {  
  26.   
  27.         @Override  
  28.         public boolean onScroll(MotionEvent e1, MotionEvent e2,  
  29.                 float distanceX, float distanceY) {  
  30.             /** 
  31.              * 如果我们滚动更接近水平方向,返回false,让子视图来处理它 
  32.              */  
  33.             return (Math.abs(distanceY) > Math.abs(distanceX));  
  34.         }  
  35.     }  
  36. }  

再将xml中的ScrollView改为<xxx.xxx.xxx.VerticalScrollView>即包名.重写的ScrollView的类名)即可。 
本方法同样适用于ScrollView中ListView等其他View无法滚动。 

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值