Scroller的学习

一直对Scroller这个类不太熟悉,之前老是在网上找着看,但是过不了多长时间后就忘记了,今天来整理一下

先看一下Scroller里面的方法:

http://api.apkbus.com/reference/android/widget/Scroller.html

为了理解方便,拿SlideView来做说明,关于SlideView的demo网上有很多,这里为了讲解主要贴出SlideView:

<span style="font-size:14px;">public class SlideView extends LinearLayout {
	  private Context mContext;

	    private LinearLayout mViewContent;

	    private LinearLayout mHolder;

	    private TextView tv_delete;

	    // 弹性滑动对象,实现View平滑滚动的一个帮助类
	    private Scroller mScroller;

	    // 滑动回调接口,用来向上层通知滑动事件
	    private OnSlideListener mOnSlideListener;

	    private int mHolderWidth = 100;

	    private int mLastX = 0;

	    private int mLastY = 0;

	    private static final int TAN = 2;

	    public SlideView(Context context) {
	        super(context);
	        initView();
	    }

	    public SlideView(Context context, AttributeSet attrs) {
	        super(context, attrs);
	        initView();
	    }

	    private void initView(){
	        mContext = getContext();
	        mScroller = new Scroller(mContext);
	        setOrientation(LinearLayout.HORIZONTAL);
	        setGravity(Gravity.CENTER_VERTICAL);
	        //将R.layout.slide_view 添加到this, View view=View.inflate(this,R.layout.*,null);是生成一个新的View
	        View.inflate(mContext, R.layout.slide_view, this);
	        mViewContent = (LinearLayout)findViewById(R.id.view_content);
	        mHolder = (LinearLayout)findViewById(R.id.holder);

	        tv_delete = (TextView)findViewById(R.id.delete);

	    }

	    public void setButtonText(CharSequence text){
	        tv_delete.setText(text);
	    }

	    public void setContentView(View view){
	        mViewContent.addView(view);
	    }

	    public void onRequireTouchEvent(MotionEvent event){
	    		// 获取点击的坐标
	            int x = (int)event.getX();
	            int y = (int)event.getY();
	            //相对于开始偏移的位置
	            int scrollX = getScrollX();
	            switch (event.getAction()){
	                case MotionEvent.ACTION_DOWN:
	                    if(!mScroller.isFinished()){
	                        mScroller.abortAnimation();
	                    }
	                    if(mOnSlideListener != null){
	                        mOnSlideListener.onSlide(this, OnSlideListener.SLIDE_STATUS_START_SCROLL);
	                    }

	                    break;

	                case MotionEvent.ACTION_MOVE:
	                	//增量
	                    int deltaX = x - mLastX;
	                    int deltaY = y - mLastY;
	                    if(Math.abs(deltaX) < Math.abs(deltaY)*TAN){
	                        // 滑动不满足条件 不做横向滑动
	                        break;
	                    }
	                    //这个SlideView偏移的距离减去手指这次move的相对于上次move的增量(相对偏移量?)
	                    int newScrollX = scrollX - deltaX;
	                    if(deltaX != 0){
	                        if(newScrollX < 0){
	                            newScrollX = 0;
	                        }else if(newScrollX > mHolderWidth){
	                            newScrollX = mHolderWidth;
	                        }
	                        //将SlideView移动到(newScrollX, 0)这个坐标点位置,并触发computeScroll()
	                        this.scrollTo(newScrollX, 0);
	                    }

	                    break;

	                case MotionEvent.ACTION_UP:
	                    int newScrollx = 0;
	                    //如果SlideView的偏移量大于默认要滑动距离的3/4,newScrollx=mHolderWidth,否则 newScrollx = 0;
	                    if(scrollX - mHolderWidth*0.75 > 0){
	                        newScrollx = mHolderWidth;
	                    }

	                    this.smoothScrollTo(newScrollx, 0);
	                    // 通知上层滑动事件
	                    if(mOnSlideListener != null){
	                        mOnSlideListener.onSlide(this, newScrollx == 0 ? OnSlideListener.SLIDE_STATUS_OFF
	                                : OnSlideListener.SLIDE_STATUS_ON);
	                    }

	                    break;

	                default:
	                    break;
	            }

	            mLastX = x;
	            mLastY = y;
	    }

	    /**
	     * 调用此方法滚动到目标位置
	     * @param fx  目标x坐标
	     * @param fy  目标Y坐标
	     */
	    private void smoothScrollTo(int fx, int fy){
	        int scrollX = getScrollX();
	        int dx = fx - scrollX;

	        int scrollY = getScrollY();
	        int dy = fy - scrollY;
	        //手指up之后从现在的位置偏移到scrollX+dx位置,dx是增量,触发computeScroll
	        mScroller.startScroll(scrollX, scrollY, dx, dy, Math.abs((dx)*3));

	        invalidate();
	    }

	    /**
	     * 由mScroller记录/计算好View滚动的位置后,最后由View的computeScroll(),完成实际的滚动
	     */
	    @Override
	    public void computeScroll() {
	        //先判断mScroller滚动是否完成
	        if(mScroller.computeScrollOffset()){
	            //这里调用View的scrollTo()完成实际的滚动
	            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
	            //必须调用该方法,否则不一定能看到滚动效果
	            postInvalidate();
	        }
	        super.computeScroll();
	    }

	    /**
	     * 设置滑动回调
	     * @param onSlideListener
	     */
	    public void setOnSlideListener(OnSlideListener onSlideListener){
	        this.mOnSlideListener = onSlideListener;
	    }

	    public interface OnSlideListener {
	        public static final int SLIDE_STATUS_OFF = 0;
	        public static final int SLIDE_STATUS_START_SCROLL = 1;
	        public static final int SLIDE_STATUS_ON = 2;

	        public void onSlide(View view, int status);
	    }

}</span>

先说一下实现的具体思路,SlideView是一个横向LinearLayout,作为父布局,它里面有两个child(当然可以更多),第一个child设置宽度充满整个父布局,这样的第二个child就会被挤出屏幕外面,要明确一点SlideView是无穷大的,你看到的只是屏幕显示的那一块,然后通过SlideView的scrollTo,让SlideView整个平移,这样第二个child就会显示出来

具体讲解一下:

1.ACTION_DOWN:mScroller停止动画,这个没什么说的

2.ACTION_MOVE:举个例子:SlideView已经偏移了scrollX,你下次move触发的时候只需要偏移scrollX - deltaX就可以了,scrollTo是相对于上次偏移,getScrollX却是向对于开始时的位置

3.ACTION_UP:在UP之前可以看到mScroller没有做任何关于滚动的的动作,up的时候调用了

<span style="font-size:14px;">	    private void smoothScrollTo(int fx, int fy){
	        int scrollX = getScrollX();
	        int dx = fx - scrollX;

	        int scrollY = getScrollY();
	        int dy = fy - scrollY;
	        //手指up之后从现在的位置偏移到scrollX+dx位置,dx是增量,触发computeScroll
	        mScroller.startScroll(scrollX, scrollY, dx, dy, Math.abs((dx)*3));

	        invalidate();
	    }</span>

触发了computeScroll()

<span style="font-size:14px;">   @Override
	    public void computeScroll() {
	        //先判断mScroller滚动是否完成
	        if(mScroller.computeScrollOffset()){
	            //这里调用View的scrollTo()完成实际的滚动
	            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
	            //必须调用该方法,否则不一定能看到滚动效果
	            postInvalidate();
	        }
	        super.computeScroll();
	    }</span>

computeScroll里面做了什么??先mScroller.computeScrollOffset()判断mScroller滚动是否完成,computeScrollOffset做了什么呢?

<span style="font-size:14px;"> public boolean computeScrollOffset() {
        if (mFinished) {
            return false;
        }

        int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);

        if (timePassed < mDuration) {
            switch (mMode) {
            case SCROLL_MODE:
                float x = timePassed * mDurationReciprocal;

                if (mInterpolator == null)
                    x = viscousFluid(x);
                else
                    x = mInterpolator.getInterpolation(x);

                mCurrX = mStartX + Math.round(x * mDeltaX);
                mCurrY = mStartY + Math.round(x * mDeltaY);
                break;
}</span>
<span style="font-size:14px;">    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        mMode = SCROLL_MODE;
        mFinished = false;
        mDuration = duration;
        mStartTime = AnimationUtils.currentAnimationTimeMillis();
        mStartX = startX;
        mStartY = startY;
        mFinalX = startX + dx;
        mFinalY = startY + dy;
        mDeltaX = dx;
        mDeltaY = dy;
        mDurationReciprocal = 1.0f / (float) mDuration;
    }</span>

可以看出int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);mStartTime = AnimationUtils.currentAnimationTimeMillis();获取过了多长时间,

然后if (timePassed < mDuration) ,看一下有没有到达设置的时间,

然后一通计算mCurrX = mStartX + Math.round(x * mDeltaX);(计算是为了在mDuration时间内完成滚动dx)得到mCurrX

,然后回到computeScroll(), scrollTo(mScroller.getCurrX(), mScroller.getCurrY());在次偏移mCurrX ,

然后回调computeScroll,直到滚动结束

时间: 2024-08-04 00:43:09

Scroller的学习的相关文章

Android 仿 窗帘效果 和 登录界面拖动效果 (Scroller类的应用) 附 2个DEMO及源代码

在android学习中,动作交互是软件中重要的一部分.当中的Scroller就是提供了拖动效果的类,在网上.比方说一些Launcher实现滑屏都能够通过这个类去实现.以下要说的就是上次Scroller类学习的后的实践了. 假设你还不了解Scroller类,那请先点击:Android 界面滑动实现---Scroller类 从源代码和开发文档中学习(让你的布局动起来) 了解之后再阅读下面内容.你会发现原来实现起来非常easy. 之前说到过.在广泛使用的側边滑动导航开源库 --SlidingLayer

Android 仿 窗帘效果 和 登录界面拖动效果 (Scroller类的应用) 附 2个DEMO及源码

在android学习中,动作交互是软件中重要的一部分,其中的Scroller就是提供了拖动效果的类,在网上,比如说一些Launcher实现滑屏都可以通过这个类去实现.下面要说的就是上次Scroller类学习的后的实践了. 如果你还不了解Scroller类,那请先点击:Android 界面滑动实现---Scroller类 从源码和开发文档中学习(让你的布局动起来) 了解之后再阅读以下内容,你会发现原来实现起来很简单. 之前说到过,在广泛使用的侧边滑动导航开源库 --SlidingLayer其实就是

2016年最牛逼的分类Android项目源码免费一次性打包下载!

之前发过一个帖子,但是那个帖子有点问题我就重新发一个吧,下面的源码是我从今年开始不断整理源码区和其他网站上的安卓例子源码,目前总共有810套左右,根据实现的功能被我分成了100多个类,总共接近2.5G,还在不断更新.初学者可以快速方便的找到自己想要的例子,大神也可以看一下别人的方法实现.虽然的例子都是我一个人辛辛苦苦花了很多时间和精力整理的,但是既然这些例子是来自于社区那就让他们免费回归社区吧,(是的!特么的不要一分钱!最看不起那些挂羊头卖狗的)你可以在本帖里面按Ctrl+F查找你需要的关键字,

android源码大放送(实战开发必备),免费安卓demo源码,例子大全文件详细列表

免费安卓demo源码,例子大全文件详细列表 本列表源码永久免费下载地址:http://www.jiandaima.com/blog/android-demo 卷 yunpan 的文件夹 PATH 列表 卷序列号为 0000-73EC E:. │ jiandaima.com文件列表生成.bat │ 例子大全说明.txt │ 本例子永久更新地址~.url │ 目录列表2016.03.10更新.txt │ ├─前台界面 │ ├─3D标签云卡片热门 │ │ Android TagCloudView云标签

转--2014年最新810多套android源码2.46GB免费一次性打包下载

转载自:http://www.eoeandroid.com/thread-497046-1-1.html 感谢该博客主人无私奉献~~ 下面的源码是从今年3月份开始不断整理源码区和其他网站上的安卓例子源码,目前总共有810套左右,根据实现的功能被博主分成了100多个类,总共接近2.5G,还在不断更新.初学者可以快速方便的找到自己想要的例子,大神也可以看一下别人的方法实现.虽然的例子都是博主一个人辛辛苦苦花了很多时间和精力整理的,但是既然这些例子是来自于社区那就让他们免费回归社区吧,(是的!特么的不

ym——android源代码大放送(实战开发必备)

转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! 目录 PATH 列表 卷序列号为 000A-8F50 E:. │  javaapk.com文件列表生成工具.bat │  使用说明.txt │  免费下载很多其它源代码.url │  文件夹列表.txt │ ├─android web应用 │      jqmDemo_static.zip │      jqmMobileDemo-master.zip │      jqmMobil

ym——android源码大放送(实战开发必备)

文件夹 PATH 列表 卷序列号为 000A-8F50 E:. │  javaapk.com文件列表生成工具.bat │  使用说明.txt │  免费下载更多源码.url │  目录列表.txt │ ├─android web应用 │      jqmDemo_static.zip │      jqmMobileDemo-master.zip │      jqmMobileDemo1_1-master.zip │      Location1014.rar │ ├─anko │      

2014年最新720多套Android源码2.0GB免费一次性打包下载

之前发过一个帖子,但是那个帖子有点问题我就重新发一个吧,下面的源码是我从今年3月份开始不断整理源码区和其他网站上的android源码,目前总共有720套左右,根据实现的功能被我分成了100多个类,总共2G多,还在不断更新安卓源码.初学者可以快速方便的找到自己想要的例子,大神也可以看一下别人的方法实现.虽然的例子都是我一个人辛辛苦苦花了很多时间和精力整理的,但是既然这些例子是来自于社区那就让他们免费回归社区吧,(是的!特么的不要一分钱!最看不起那些挂羊头卖狗的)你可以在本帖里面按Ctrl+F查找你

Android学习Scroller(五)——详解Scroller调用过程以及View的重绘

MainActivity如下: package cc.ww; import android.os.Bundle; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import android.widget.RelativeLayout; import android.widget.RelativeLayout.LayoutParams; import android.app.Activity;