Scroller弹性滑动

本文介绍了如何利用Scroller实现弹性滑动,通过Scroller的getFinalX()和getFinalY()计算运动距离,startScroll()方法启动滑动,invalidate()确保界面更新,computeScroll()方法处理弹性效果。代码示例展示了在LinearLayout中的应用。
摘要由CSDN通过智能技术生成
Android系统的滑动效果往往比较生硬,用户体验和粘着性方面如果要提高的话,弹性滑动是比较好的利器。实现

弹性滑动可以有好几种方式,其中利用Scroller实现弹性滑动是一种不错的方式。
首先,从源码层面看一下为什么Scroller为什么能实现弹性滑动。

   /**
     * 滚动到目标位置
     *
     * @param destX
     * @param destY
     */
    protected void smoothScrollTo(int destX, int destY) {
        int scrollX = mScroller.getFinalX()
        int scrollY = mScroller.getFinalY()
        int dx = destX - scrollX;
        int dy = destY - scrollY
        mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);
        invalidate();
    }

    @Override
    public void computeScroll() {
        //判断mScroller滚动是否完成
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            //必须调用该方法,否则不一定能看到滚动效果
            postInvalidate();
        }
        super.computeScroll();
    }
smoothScrollTo(int destX, int destY)方法的两个参数分别是View子空间(内容)滑动的目标横坐标和纵坐标。

mScroller.getFinalX()表示的是运动前的横坐标,所以int dx = destX - mScroller.getFinalX()表示的就是运动的相对
距离。对于纵纵坐标也是如此。
mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy),这个方法的参数有必要说明一下。第
一、二个参数分别表示的是View内容的原始坐标,第三、四个参数表示的是运动的相对距离(单位是像素),最后
一个参数表示的运动的时间长度。
invalidate()非常重要,只有调用这个方法才能后面的computeScroll()方法的调用,否则的话不一定会刷新界面,用户就会
看不到滚动效果。
再看computeScroll()方法,正是因为这个方法View才实现了弹性滑动。其中,mScroller.computeScrollOffset()返回的是一个
bool量,代表是否完成滑动,如果完成了滑动则返回true,否则返回false。
当View重绘后会在draw方法中调用computerScroll,而computerScroll又会去向Scroller获取当前的scrollX和scrollY;然后通过
scrollTo方法实现滑动;接着又调用postInvalidate方法来进行第二次重绘,这次重绘的过程和第一次重绘一样,还是会导致computerScroll
方法被调用;然后继续向scroller获取当前的scrollerX和scrollerY,并通过scrollTo方法滑动到新的位置,如是反复,直到整个滑动过程结束。
下面附上一段项目代码,该代码利用了Scroller实现了弹性滑动的LinearLayout布局视图。希望给大家带来帮助。

public class ElasticLinearLayout extends LinearLayout {

    private static final String TAG = ElasticLinearLayout.class.getSimpleName();
    private Scroller mScroller;
    private GestureDetector mGestureDetector;

    public ElasticLinearLayout(Context context) {
        this(context, null);
    }

    public ElasticLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        setClickable(true);
        setLongClickable(true);
        mScroller = new Scroller(context);
        mGestureDetector = new GestureDetector(context, new GestureDetector.OnGestureListener(){
            @Override
        public boolean onDown(MotionEvent e) {
            // TODO Auto-generated method stub
            return true;
        }

        @Override
        public void onShowPress(MotionEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            // TODO Auto-generated method stub
            return false;
        }

        /**
         *
         * @param e1  第1个ACTION_DOWN MotionEvent
         * @param e2  最后一个ACTION_MOVE MotionEvent
         * @param distanceX  距离上次产生onScroll事件后,X抽移动的距离
         * @param distanceY  距离上次产生onScroll事件后,Y抽移动的距离
         * @return
         */
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            int disX = (int) ((distanceX - 0.5) / 2);
            int disY = (int) ((distanceY - 0.5) / 2);
            smoothScrollBy(disX, disY);
            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            // TODO Auto-generated method stub
            return false;
        }
        });
    }

    /**
     * 滚动到目标位置
     *
     * @param destX
     * @param destY
     */
    protected void smoothScrollTo(int destX, int destY) {
        int dx = destX - mScroller.getFinalX();
        int dy = destY - mScroller.getFinalY();
        smoothScrollBy(dx, dy);
    }

    /**
     * 设置滚动的相对偏移
     *
     * @param dx
     * @param dy
     */
    protected void smoothScrollBy(int dx, int dy) {
        mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);
        invalidate();
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
        super.computeScroll();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                smoothScrollTo(0, 0);
                break;
            default:
                return mGestureDetector.onTouchEvent(event);
        }
        return super.onTouchEvent(event);
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值