原帖:
或者另一种实现方式(推荐)
通过上面的方法,也可以实现有弹性的ListView:
左右滑动加弹性的HorizontalScrollView
也可以这样实现有弹性的HorizontalScrollView: (推荐)
另付:
自定义ScrollView,以解决viewflipper 与scrollview的手势冲突
如何解决ViewPager在ScrollView中滑动经常失效、无法正常滑动问题?(推荐)
解决方法只需要在接近水平滚动时ScrollView不处理事件而交由其子View(即这里的ViewPager)处理即可,重写ScrollView的onInterceptTouchEvent函数,如下:
再将xml中的ScrollView改为<xxx.xxx.xxx.VerticalScrollView>即包名.重写的ScrollView的类名)即可。
本方法同样适用于ScrollView中ListView等其他View无法滚动。
http://dev.10086.cn/cmdn/bbs/thread-40685-1-1.html
- import android.content.Context;
- import android.graphics.Rect;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.animation.TranslateAnimation;
- import android.widget.ScrollView;
- /**
- * ElasticScrollView有弹性的ScrollView
- */
- public class ElasticScrollView extends ScrollView {
- private View inner;
- private float y;
- private Rect normal = new Rect();;
- public ElasticScrollView(Context context) {
- super(context);
- }
- public ElasticScrollView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- @Override
- protected void onFinishInflate() {
- if (getChildCount() > 0) {
- inner = getChildAt(0);
- }
- }
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if (inner == null) {
- return super.onTouchEvent(ev);
- } else {
- commOnTouchEvent(ev);
- }
- return super.onTouchEvent(ev);
- }
- public void commOnTouchEvent(MotionEvent ev) {
- int action = ev.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- y = ev.getY();
- break;
- case MotionEvent.ACTION_UP:
- if (isNeedAnimation()) {
- animation();
- }
- break;
- case MotionEvent.ACTION_MOVE:
- final float preY = y;
- float nowY = ev.getY();
- int deltaY = (int) (preY - nowY);
- // 滚动
- scrollBy(0, deltaY);
- y = nowY;
- // 当滚动到最上或者最下时就不会再滚动,这时移动布局
- if (isNeedMove()) {
- if (normal.isEmpty()) {
- // 保存正常的布局位置
- normal.set(inner.getLeft(), inner.getTop(), inner
- .getRight(), inner.getBottom());
- }
- // 移动布局
- inner.layout(inner.getLeft(), inner.getTop() - deltaY, inner
- .getRight(), inner.getBottom() - deltaY);
- }
- break;
- default:
- break;
- }
- }
- // 开启动画移动
- public void animation() {
- // 开启移动动画
- TranslateAnimation ta = new TranslateAnimation(0, 0, inner.getTop(),
- normal.top);
- ta.setDuration(200);
- inner.startAnimation(ta);
- // 设置回到正常的布局位置
- inner.layout(normal.left, normal.top, normal.right, normal.bottom);
- normal.setEmpty();
- }
- // 是否需要开启动画
- public boolean isNeedAnimation() {
- return !normal.isEmpty();
- }
- // 是否需要移动布局
- public boolean isNeedMove() {
- int offset = inner.getMeasuredHeight() - getHeight();
- int scrollY = getScrollY();
- if (scrollY == 0 || scrollY == offset) {
- return true;
- }
- return false;
- }
- }
- <?xml version="1.0" encoding="utf-8"?>
- <com.rebound.myscroll.ElasticScrollView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:id="@+id/sv"
- android:layout_height="fill_parent"
- >
- <TextView android:id="@+id/tv"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="......一个很长很长的字符串......"
- />
- </com.rebound.myscroll.ElasticScrollView>
或者另一种实现方式(推荐)
- import android.content.Context;
- import android.util.AttributeSet;
- import android.util.DisplayMetrics;
- import android.widget.ScrollView;
- public class MtScrollView extends ScrollView {
- private static final int MAX_Y_OVERSCROLL_DISTANCE = 200;
- private Context mContext;
- private int mMaxYOverscrollDistance;
- public MtScrollView(Context context){
- super(context);
- mContext = context;
- initBounceListView();
- }
- public MtScrollView(Context context, AttributeSet attrs){
- super(context, attrs);
- mContext = context;
- initBounceListView();
- }
- public MtScrollView(Context context, AttributeSet attrs, int defStyle){
- super(context, attrs, defStyle);
- mContext = context;
- initBounceListView();
- }
- private void initBounceListView(){
- final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
- final float density = metrics.density;
- mMaxYOverscrollDistance = (int) (density * MAX_Y_OVERSCROLL_DISTANCE);
- }
- @Override
- protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent){
- //这块是关键性代码
- return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mMaxYOverscrollDistance, isTouchEvent);
- }
- }
通过上面的方法,也可以实现有弹性的ListView:
- public class BounceListView extends ListView
- {
- private static final int MAX_Y_OVERSCROLL_DISTANCE = 200;
- private Context mContext;
- private int mMaxYOverscrollDistance;
- public BounceListView(Context context)
- {
- super(context);
- mContext = context;
- initBounceListView();
- }
- public BounceListView(Context context, AttributeSet attrs)
- {
- super(context, attrs);
- mContext = context;
- initBounceListView();
- }
- public BounceListView(Context context, AttributeSet attrs, int defStyle)
- {
- super(context, attrs, defStyle);
- mContext = context;
- initBounceListView();
- }
- private void initBounceListView()
- {
- //get the density of the screen and do some maths with it on the max overscroll distance
- //variable so that you get similar behaviors no matter what the screen size
- final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
- final float density = metrics.density;
- mMaxYOverscrollDistance = (int) (density * MAX_Y_OVERSCROLL_DISTANCE);
- }
- @Override
- protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent)
- {
- //This is where the magic happens, we have replaced the incoming maxOverScrollY with our own custom variable mMaxYOverscrollDistance;
- return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mMaxYOverscrollDistance, isTouchEvent);
- }
- }
左右滑动加弹性的HorizontalScrollView
- import android.content.Context;
- import android.graphics.Rect;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.animation.TranslateAnimation;
- import android.widget.HorizontalScrollView;
- public class ElasticHorizontalScrollView extends HorizontalScrollView {
- private View inner;
- private Rect normal = new Rect();
- private float x;
- public ElasticHorizontalScrollView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- public ElasticHorizontalScrollView(Context context) {
- super(context);
- }
- @Override
- protected void onFinishInflate() {
- if (getChildCount() > 0) {
- inner = getChildAt(0);
- }
- super.onFinishInflate();
- }
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if (ev == null) {
- return super.onTouchEvent(ev);
- } else {
- commOnTouchEvent(ev);
- }
- return super.onTouchEvent(ev);
- }
- private void commOnTouchEvent(MotionEvent ev) {
- int action = ev.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- x = ev.getX();
- break;
- case MotionEvent.ACTION_UP:
- if (isNeedAnimation()) {
- animation();
- }
- break;
- case MotionEvent.ACTION_MOVE:
- final float preX = x;
- float nowX = ev.getX();
- int distanceX = (int) (preX - nowX);
- scrollBy(distanceX, 0);
- x = nowX;
- if (isNeedMove()) {
- if (normal.isEmpty()) {
- normal.set(inner.getLeft(), inner.getTop(), inner.getRight(), inner.getBottom());
- }
- inner.layout(inner.getLeft() - distanceX, inner.getTop(), inner.getRight() - distanceX, inner.getBottom());
- }
- break;
- default:
- break;
- }
- }
- private void animation() {
- TranslateAnimation mTranslateAnimation = new TranslateAnimation(inner.getLeft(), 0, normal.left, 0);
- mTranslateAnimation.setDuration(50);
- inner.setAnimation(mTranslateAnimation);
- inner.layout(normal.left, normal.top, normal.right, normal.bottom);
- normal.setEmpty();
- }
- private boolean isNeedAnimation() {
- return !normal.isEmpty();
- }
- private boolean isNeedMove() {
- int offset = inner.getMeasuredWidth() - getWidth();
- int scrollX = getScrollX();
- if (scrollX == 0 || offset == scrollX)
- return true;
- return false;
- }
- }
- <com.example.horiztalscrollviewtext.ElasticHorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#D1EEEE"
- android:scrollbars="none" >
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="#F5F5F5"
- android:orientation="horizontal" >
- <ImageView
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:src="@drawable/main_guide_0" />
- <ImageView
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:src="@drawable/main_guide_0" />
- <ImageView
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:src="@drawable/main_guide_0" />
- </LinearLayout>
- </com.example.horiztalscrollviewtext.ElasticHorizontalScrollView>
也可以这样实现有弹性的HorizontalScrollView: (推荐)
- import android.content.Context;
- import android.util.AttributeSet;
- import android.util.DisplayMetrics;
- import android.widget.HorizontalScrollView;
- public class BouncyHScrollView extends HorizontalScrollView {
- private static final int MAX_X_OVERSCROLL_DISTANCE = 200;
- private Context mContext;
- private int mMaxXOverscrollDistance;
- public BouncyHScrollView(Context context) {
- super(context);
- // TODO Auto-generated constructor stub
- mContext = context;
- initBounceDistance();
- }
- public BouncyHScrollView(Context context, AttributeSet attrs) {
- super(context, attrs);
- // TODO Auto-generated constructor stub
- mContext = context;
- initBounceDistance();
- }
- public BouncyHScrollView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- // TODO Auto-generated constructor stub
- mContext = context;
- initBounceDistance();
- }
- private void initBounceDistance(){
- final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
- mMaxXOverscrollDistance = (int) (metrics.density * MAX_X_OVERSCROLL_DISTANCE);
- }
- @Override
- protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent){
- //这块是关键性代码
- return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, mMaxXOverscrollDistance, maxOverScrollY, isTouchEvent);
- }
- }
另付:
自定义ScrollView,以解决viewflipper 与scrollview的手势冲突
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.GestureDetector;
- import android.view.MotionEvent;
- import android.widget.ScrollView;
- /**
- * 自定义ScrollView,并重写其onTouchEvent和dispatchTouchEvent方法,
- * 以解决viewflipper 与scrollview的手势冲突
- * @author yangjiantong
- *
- */
- public class MyScrollView extends ScrollView {
- GestureDetector gestureDetector;
- public MyScrollView(Context context) {
- super(context);
- // TODO Auto-generated constructor stub
- }
- public MyScrollView(Context context, AttributeSet attrs) {
- super(context, attrs);
- // TODO Auto-generated constructor stub
- }
- public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- // TODO Auto-generated constructor stub
- }
- public void setGestureDetector(GestureDetector gestureDetector) {
- this.gestureDetector = gestureDetector;
- }
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- // TODO Auto-generated method stub
- super.onTouchEvent(ev);
- return gestureDetector.onTouchEvent(ev);
- }
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev){
- gestureDetector.onTouchEvent(ev);
- super.dispatchTouchEvent(ev);
- return true;
- }
- }
如何解决ViewPager在ScrollView中滑动经常失效、无法正常滑动问题?(推荐)
解决方法只需要在接近水平滚动时ScrollView不处理事件而交由其子View(即这里的ViewPager)处理即可,重写ScrollView的onInterceptTouchEvent函数,如下:
- package cc.newnews.view;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.GestureDetector;
- import android.view.GestureDetector.SimpleOnGestureListener;
- import android.view.MotionEvent;
- import android.widget.ScrollView;
- public class VerticalScrollView extends ScrollView {
- private GestureDetector mGestureDetector;
- public VerticalScrollView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mGestureDetector = new GestureDetector(context, new YScrollDetector());
- }
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- return super.onInterceptTouchEvent(ev)
- && mGestureDetector.onTouchEvent(ev);
- }
- class YScrollDetector extends SimpleOnGestureListener {
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
- /**
- * 如果我们滚动更接近水平方向,返回false,让子视图来处理它
- */
- return (Math.abs(distanceY) > Math.abs(distanceX));
- }
- }
- }
再将xml中的ScrollView改为<xxx.xxx.xxx.VerticalScrollView>即包名.重写的ScrollView的类名)即可。
本方法同样适用于ScrollView中ListView等其他View无法滚动。