| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> Android应用开发Scroller详解及源码浅析 -> 正文阅读 |
|
[移动开发]Android应用开发Scroller详解及源码浅析 |
mRightView = getChildAt(1); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getActionMasked()) { case MotionEvent.ACTION_DOWN: mInitX = ev.getX(); mInitY = ev.getY(); super.dispatchTouchEvent(ev); return true; case MotionEvent.ACTION_MOVE: //>0为手势向右下 mOffsetX = ev.getX() - mInitX; mOffsetY = ev.getY() - mInitY; //横向手势跟随移动 if (Math.abs(mOffsetX) - Math.abs(mOffsetY) > ViewConfiguration.getTouchSlop()) { int offset = (int) -mOffsetX; if (getScrollX() + offset > mRightView.getWidth() || getScrollX() + offset < 0) { return true; } this.scrollBy(offset, 0); mInitX = ev.getX(); mInitY = ev.getY(); return true; } break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: //松手时刻滑动 int offset = ((getScrollX() / (float)mRightView.getWidth()) > 0.5) ? mRightView.getWidth() : 0; // this.scrollTo(offset, 0); mScroller.startScroll(this.getScrollX(), this.getScrollY(), offset-this.getScrollX(), 0); invalidate(); mInitX = 0; mInitY = 0; mOffsetX = 0; mOffsetY = 0; break; } return super.dispatchTouchEvent(ev); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { this.scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } } } 简单吧,使用Scroller就能这么优雅的滑动,不解释,简单的Demo,哈哈;有了这个基本映像我们直接高速——源码探测,搞清源码基本原理流程就能用的顺手喽。 【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我】 3 Scroller源码浅析 ================== 通过上面实例我们可以发现在自定义View的过程中使用Scroller的流程如下图所示: 既然有了这么明确的流程图,那我们下面就来依据这个流程简单分析下Scroller的源码。可以发现Scroller这类的代码不多哇,确实是一个工具类,哈哈,我们先看下构造方法: public Scroller(Context context) { this(context, null); } public Scroller(Context context, Interpolator interpolator) { this(context, interpolator, context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB); } public Scroller(Context context, Interpolator interpolator, boolean flywheel) { mFinished = true; if (interpolator == null) { mInterpolator = new ViscousFluidInterpolator(); } else { mInterpolator = interpolator; } mPpi = context.getResources().getDisplayMetrics().density * 160.0f; //摩擦力计算单位时间减速度 mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction()); mFlywheel = flywheel; mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning } 可以看见,构造方法没啥特殊的,只是一些基础的设置,唯一要重点关注可能自定义的也就动画插值器那个参数了,默认是ViscousFluidInterpolator的(不懂动画插值器的请看《Android应用开发之所有动画使用详解》),我们可以自定义修改。两参构造方法中其实也就是对第三个参数做了HONEYCOMB兼容性处理,三参是所有构造方法最终调运的方法,其实也就是初始化了一些变量而已,没啥重要的。 下面我们看看与Scroller相关的startScroll()和fling()方法,源码如下: //在我们想要滚动的地方调运,准备开始滚动,默认滚动时间为DEFAULT_DURATION public void startScroll(int startX, int startY, int dx, int dy) { startScroll(startX, startY, dx, dy, DEFAULT_DURATION); } //在我们想要滚动的地方调运,准备开始滚动,手动设置滚动时间 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; } //在快速滑动松开的基础上开始惯性滚动,滚动距离取决于fling的初速度 public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) { … mMode = FLING_MODE; mFinished = false; … mStartX = startX; mStartY = startY; … mDistance = (int) (totalDistance * Math.signum(velocity)); mMinX = minX; mMaxX = maxX; mMinY = minY; mMaxY = maxY; … mFinalY = Math.min(mFinalY, mMaxY); mFinalY = Math.max(mFinalY, mMinY); } 可以看见,上面这几个美其名曰滑动的Scroller方法其实都只是一个幌子,没有进行滑动,而是初始化了一堆成员变量;譬如滚动模式、开始时间、持续时间等,也就是说他们都只是工具方法而已,实质的滑动其实是需要我们在他后面手动调运View的invalidate()进行刷新,然后在View进行刷新时又会调运自己的View.computeScroll()方法(不了解View绘制的请看《Android应用层View绘制流程与源码分析》一文),在View.computeScroll()方法中进行Scroller.computeScrollOffset()判断与触发View的滑动方法。 既然这样那我们粗略给出View的绘制流程,详细的请看《Android应用层View绘制流程与源码分析》一文。当我们调运invalidate()会触发View的如下方法: public void draw(Canvas canvas) { … /*
*/ … // Step 4, draw the children dispatchDraw(canvas); … } 可以发现,View的draw()方法被触发时总共会进行6步,最重要的一步我们看第四步,下面是第四步dispatchDraw()方法源码: protected void dispatchDraw(Canvas canvas) {} 可以看见,View的该方法为空方法,那我们看下他子类ViewGroup的该方法,如下: protected void dispatchDraw(Canvas canvas) { … for (int i = 0; i < childrenCount; i++) { … more |= drawChild(canvas, child, drawingTime); … } … } 可以发现,ViewGroup的dispatchDraw()方法实质又跑到了drawChild()方法,如下: protected boolean drawChild(Canvas canvas, View child, long drawingTime) { return child.draw(canvas, this, drawingTime); } 额额,实质又是child的另一个draw()方法而已,我们回到View去看下这个方法,如下: boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { … if (!drawingWithRenderNode) { computeScroll(); sx = mScrollX; sy = mScrollY; } … } 额额,这就解释了为何View调运invalidate()就会触发computeScroll()方法了。而ViewGroup最终调运scrollTo()方法都只能滚动内部子View的问题其实是因为ViewGroup它本身并没有任何可画的东西,它是一个透明的控件,所以一般不会触发onDraw()方法,但是当你给他设置背景等就会调用onDraw方法了,可是走的是绘制背景流程。 View相关的扯完了,下面我们来看看Scroller的computeScrollOffset()方法,下面我们简单分析这个方法,如下: //判断滚动是否还在继续,true继续,false结束 public boolean computeScrollOffset() { //mFinished为true表示已经完成了滑动,直接返回为false if (mFinished) { return false; } //mStartTime为开始时的时间戳,timePassed就是当前滑动持续时间 int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); //mDuration为我们设置的持续时间,当当前已滑动耗时timePassed小于总设置持续时间时才进入if if (timePassed < mDuration) { //mMode有两中,如果调运startScroll()则为SCROLL_MODE模式,调运fling()则为FLING_MODE模式 switch (mMode) { case SCROLL_MODE: //根据Interpolator插值器计算在该时间段里移动的距离赋值给mCurrX和mCurrY final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal); mCurrX = mStartX + Math.round(x * mDeltaX); mCurrY = mStartY + Math.round(x * mDeltaY); |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 10:58:42- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |