扩展HorizontalScrollView实现整个屏幕滚动

import java.lang.reflect.Field; 
import android.content.Context; 
import android.util.AttributeSet; 
import android.view.animation.AnimationUtils; 
import android.view.animation.Interpolator; 
import android.view.animation.OvershootInterpolator; 
import android.widget.HorizontalScrollView; 
import android.widget.OverScroller; 
import android.widget.Scroller;
 

public class HorizontalScrollViewEx extends HorizontalScrollView {
 
    static final int ANIMATED_SCROLL_GAP = 250;
    private long mLastScroll;
    private Field mScrollerField;
    ScrollerEx scrollerEx = null;
 
    public HorizontalScrollViewEx(Context context) {

        this(context, null);
     }
 
    public HorizontalScrollViewEx(Context context, AttributeSet attrs) {
 
        super(context, attrs);
        this.setSmoothScrollingEnabled(false);
         initScroller(); 
    }
 

    public HorizontalScrollViewEx(Context context, AttributeSet attrs, int defStyle) {
 
        super(context, attrs, defStyle); 
        this.setSmoothScrollingEnabled(false); 
        initScroller();
 
    }
 
   private void initScroller() {
 
        try {
 
            mScrollerField = HorizontalScrollView.class.getDeclaredField("mScroller");
             mScrollerField.setAccessible(true); 
            String type = mScrollerField.getType().getSimpleName();
 
            if ("OverScroller".equals(type)) {
 
                scrollerEx = new ScrollerEx() { 
                    private OverScroller mScroller = null; 

                    public void startScroll(int startX, int startY, int dx, int dy, int duration) { 
                        mScroller.startScroll(startX, startY, dx, dy, duration);
                     }
 
                    public boolean isFinished() {
                        return mScroller.isFinished();
                     }
 
                    public Object getScroller() {
                         return mScroller;
                     }
 
                    public void create(Context context, Interpolator interpolator) {
                        mScroller = new OverScroller(context, interpolator);
                     }
 
                    public void abortAnimation() { 
                        if (mScroller != null) {
                            mScroller.abortAnimation(); 
                        }
                     }
                 };
 
            } else {
 
                scrollerEx = new ScrollerEx() { 
                    private Scroller mScroller = null;
 
                    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
                        mScroller.startScroll(startX, startY, dx, dy, duration);
                     }
 

                    public boolean isFinished() {
                        return mScroller.isFinished(); 
                  }
 
                    public Object getScroller() {
                         return mScroller;
                     }
 
                    public void create(Context context, Interpolator interpolator) {
                         mScroller = new Scroller(context, interpolator);
                    }
 
                    public void abortAnimation() {
                         if (mScroller != null) {
 
                            mScroller.abortAnimation(); 
                        }
                     } 
                }; 
            }
        } catch (Exception ex) { 
        }
 
    }public final void smoothScrollBy(int dx, int dy, int addDuration) {
 
        float tension = 0f;
        scrollerEx.abortAnimation(); 
        Interpolator ip = new OvershootInterpolator(tension); 
        scrollerEx.create(getContext(), ip);
 

        try { 
            mScrollerField.set(this, scrollerEx.getScroller()); 
        } catch (Exception e) {
        } 

        long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll; 
        if (duration > ANIMATED_SCROLL_GAP) {
 
            scrollerEx.startScroll(getScrollX(), getScrollY(), dx, dy, addDuration);
            awakenScrollBars(); 

            // awakenScrollBars(mScroller.getDuration());
            invalidate(); 
        } else {
 
            if (!scrollerEx.isFinished()) { 
                scrollerEx.abortAnimation();
             }
 
            scrollBy(dx, dy);
         }
 
        mLastScroll = AnimationUtils.currentAnimationTimeMillis();
    }
 
    public final void smoothScrollTo(int x, int y, int duration) {
        smoothScrollBy(x - getScrollX(), y - getScrollY(), duration);
 
    }
 
    private interface ScrollerEx {
 
        void create(Context context, Interpolator interpolator);
         Object getScroller();
         void abortAnimation();
         void startScroll(int startX, int startY, int dx, int dy, int duration);
         boolean isFinished();
     }
 }
 

核心部分是利用反射的方法取得父类的 mScroller对象,然后再使用 mScroller控制滚动。
然后在Activity里重写dispatchTouchEvent方法,使用GestureDetector控制滚动距离。 下面是部分代码

 
    private HorizontalScrollViewEx hsvMain;
 
    @Override 
    public void onCreate(Bundle savedInstanceState) {
 
        super.onCreate(savedInstanceState);
  
      hsvMain = (HorizontalScrollViewEx) findViewById(R.id.hsvMain);
  
       }
 
    // 监听屏幕动作事件 
    GestureDetector =    gestureDetector = new GestureDetector(new OnGestureListener() {
 
            private int LEFT_DISTANCE = -150; 
            private int RIGHT_DISTANCE = 150;
 
            // 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发
 
            public boolean onDown(MotionEvent e) { 
                return true; 
            }
 
            // 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 
            // 多个ACTION_MOVE, 1个ACTION_UP触发 
            // e1:第1个ACTION_DOWN MotionEvent 
            // e2:最后一个ACTION_MOVE MotionEvent 
            // velocity X:X 轴上的移动速度,像素/秒
            // velocity Y:Y 轴上的移动速度,像素/秒
 
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
 

                float distanceX = e2.getX() - e1.getX();
                if (distanceX < LEFT_DISTANCE) {
 
                    // left
                    setXPosition(true); 

                } else if (distanceX > RIGHT_DISTANCE) {
 
                    // right
                     setXPosition(false);
 
                }
 
                hsvMain.smoothScrollTo(xPosition, 0, speed); 
                return true;
 
            }
            // 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发 
            public void onLongPress(MotionEvent e) {
 
            } 
            // 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发 
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
 
                hsvMain.scrollBy((int) distanceX, 0); 
                return true;
 
            }
            // 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发 
            // 注意和onDown()的区别,强调的是没有松开或者拖动的状态
 
            public void onShowPress(MotionEvent e) {
 
            }
             // 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发
 
            public boolean onSingleTapUp(MotionEvent e) {
 
                if (e.getY() < offsetOfBottom) { 
                    return true; 
                }
 
                if (e.getX() > halfOfWidth) { 
                    setXPosition(true);
                 } else {
 
                    setXPosition(false);
 
                } 
                hsvMain.scrollTo(xPosition, 0); 
                return true;
 
            } 
        });

    @Override
 
    public boolean dispatchTouchEvent(MotionEvent ev) { 
        boolean result = gestureDetector.onTouchEvent(ev);
 
        if (result == false) {
             final int action = ev.getAction(); 
            switch (action & MotionEvent.ACTION_MASK) { 
            case MotionEvent.ACTION_UP:
 
                hsvMain.smoothScrollTo(xPosition, 0, speed); 
                result = true;
             }
 
        } 
        return true;
 
    }
 

效果:
第一页

posted on 2011-11-29 12:53  vus520  阅读(2500)  评论(1编辑  收藏  举报

导航