Android从零开搞系列:自定义View(6)ScrollTo+ScrollBy+Scroller+NestedScrolling机制(上)
来源:互联网 发布:分销商城系统源码下载 编辑:程序博客网 时间:2024/06/11 12:44
转载请注意:
http://blog.csdn.net/wjzj000/article/details/53874285
本菜开源的一个自己写的Demo,希望能给Androider们有所帮助,水平有限,见谅见谅…
https://github.com/zhiaixinyang/PersonalCollect (拆解GitHub上的优秀框架于一体,全部拆离不含任何额外的库导入)
https://github.com/zhiaixinyang/MyFirstApp(Retrofit+RxJava+MVP)
写在前面
在一切的开始之前,先看一个简单的效果:
实现这种效果有很多种方案,今天在这就主要借这个机会来记录一下scrollTo,scrollBy以及Scroller的用法。
让我们先了解一发:
关于scrollTo方法:
先看一下scrollTo()的源码解释:
/** * Set the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. * @param x the x position to scroll to * @param y the y position to scroll to */ //翻译过来:设置视图的滚动位置。 这将导致调用{@link #onScrollChanged(int,int,int,int)},并且视图将失效。
说实话不是很好理解。但是根据效果我们可以这么理解:scrollTo的效果是移向你传进的坐标。如果你再次调用这个方法,传值不变时!你会发现并没有任何的位置移动。(和scrollBy方法有区别)因为它已经到达了这个位置因此不会再移动,而scrollBy却不然。
此外此方法移动的是View内部的位置而不是View整体。如果View不是一个ViewGroup的话,例如TextView,那么移动的就是TextView的文字内容;如果是ViewGroup那么便是ViewGroup中的子元素。
关于scrollBy方法:
看一下scrollBy的源码:
//注释基本和scrollTo相同 /** * Move the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. * @param x the amount of pixels to scroll by horizontally * @param y the amount of pixels to scroll by vertically */ public void scrollBy(int x, int y) { scrollTo(mScrollX + x, mScrollY + y); }
我们可以看出,scrollBy内部是调用的scrollTo,但是这里的传参导致了它们二者的不同。
scrollBy传入了mScrollX…这是个什么东西?我们在View中可以调用getScrollX()方法拿到这个值;其实这个值就是滑动的距离,对于X轴来说左滑动为正(增加),对于Y轴上滑动为正(增加)。
scrollBy的效果与scrollTo也截然相反。scrollBy就基于当前位置的移动,简单说它可以不断的移动。
只用文字去叙述有点单调,接下来上高清无码gif:
- 这里我分别对俩这进行了多次点击,但是 传的值是固定的
!!!!这里有个需要注意的地方!!!!
在传值的时候,我们需要注意正负号问题:简单来说往左滑动时x为正,否则为负;上滑动时y为正,反之为负。
因为这里和mScrollX和mScrollY这俩个变量有关。这两个方法最终都会直接或间接的引用到这俩个变量。而它们俩的正负是这么判断的:如果View的左边缘在View内容区域(这俩个方法的移动都只是移动自己的内容区域)左边缘的右边为正,反之为负;如果View的上边缘在View内容区域的上边缘的下边mScrollY为正反之为负。
为什么是这样:当我们把内容区域的某个边缘当做参考点来理解就是这种情况。如果View的内容区域的左边缘为(0,…)那么View的左边缘在它的右边,理所应当为(+…,…)。同理mScrollY也是如此。
第三个我们来看一下Scroller
它其实就是一个辅助类:
//简单重写了onTouchEvent @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: int x=-5; //在0.2内使View的x轴从0移到x //但是具体怎么移动需要我们自己去实现,解释在下面 scroller.startScroll(0,0,x,0,200); invalidate(); break; } return true; } /** * invalidate()最终会调用computeScroll() * 而View中的computeScroll()是一个空实现 * 因此需要我们自己去重写这个方法,去实现对应的效果 */ @Override public void computeScroll() { super.computeScroll(); //如果返回true,说明滑动还不到结束的时候,应当继续。 if (scroller.computeScrollOffset()){ //而促使它滑动的方式依旧是scrollBy或是scrollTo //注意此处x的位置,我们是使用的scroller.getCurrX()的返回值,至于它的作用往下来 scrollBy(scroller.getCurrX(),0); //请求重新绘制View invalidate(); } }
Scroller这个类本身不具备任何移动View的作用。它的startScroll方法,我们进源码就会发现仅仅是一些简单的赋值。真正起到移动效果的是invalidate()方法,通过这个方法使得View重绘,因此就会调用computeScroll(),所以我们重写computeScroll()。
可能有朋友在这里会由衷的赞叹一句:尼玛SB吗?饶了这么一大圈不还是scrollTo/scrollBy么!
不不不,它有一个最重要的作用。先让我们注意一下我们在传参的时候,传了一个时间参数(200)。
这个值在computeScrollOffset()中体现它的作用:
//根据代码中的变量名,我们也能猜出:这里通过时间的流逝来计算移动进行的比例 int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); //如果时间流逝小于应该传入的值,那么就继续执行 if (timePassed < mDuration) { switch (mMode) { //如果是滚动状态 case SCROLL_MODE: //通过类插值器的效果来计算x的变化量,使其随时间进行均匀变化。 final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal); mCurrX = mStartX + Math.round(x * mDeltaX); mCurrY = mStartY + Math.round(x * mDeltaY); break; //省略部分代码 }
这里用于计算移动的比例,因此Scroller最大的效果就是移动可以随时间的变化而变化,简单说可以做一些弹性的效果。让滑动不在单点生硬。
其实理解这些方法的使用,最开始的那个效果真的很简单,所以接下来就是简单贴一下代码:
相关代码
onTouchEvent相关:
@Override public boolean onTouchEvent(MotionEvent event) { float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (!scroller.isFinished()) scroller.abortAnimation(); //记录手指按下时的坐标 lastY = y; downY=event.getY(); //消费点击事件 return true; case MotionEvent.ACTION_MOVE: float dy = y - lastY; scrollBy(0, (int) -dy); lastY = y; break; } return super.onTouchEvent(event); }
scrollTo相关:
//topViewHeight就是我们需要滑动的View的高度 @Override public void scrollTo(int x, int y) { if (y < 0) { y = 0; } if (y > topViewHeight) { y = topViewHeight; } if (y != getScrollY()) { super.scrollTo(x, y); } }
onFinishInflate相关:
//此方法在布局加载完成后回调,因此在此获得View的引用 @Override protected void onFinishInflate() { super.onFinishInflate(); topView=getChildAt(0); }
onSizeChanged相关:
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //获取topView的高度 topViewHeight = topView.getMeasuredHeight(); //画三角形所需的路线 path=new Path(); path.moveTo(avatarLeft-25,topViewHeight); path.lineTo(avatarLeft+25,topViewHeight); path.lineTo(avatarLeft,topViewHeight-25); path.close(); } //画三角形 @Override protected void dispatchDraw(Canvas canvas) { canvas.drawPath(path,paint); super.dispatchDraw(canvas); }
如果对基本的自定义View中的Canvas的一些Api不了解的可以看一下我的另一篇博客:
http://blog.csdn.net/wjzj000/article/details/53589024
PS:相关源码基本都存放于我的这个开源项目之中:
https://github.com/zhiaixinyang/PersonalCollect
尾声
OK,到此关于scrollTo和scrollBy以及Scroller的用法就结束了,接下来就是关于NestedScrolling机制的分析,让我们下一次博客见。
最后希望各位看官可以star我的GitHub,三叩九拜,满地打滚求star:
https://github.com/zhiaixinyang/PersonalCollect
https://github.com/zhiaixinyang/MyFirstApp
- Android从零开搞系列:自定义View(6)ScrollTo+ScrollBy+Scroller+NestedScrolling机制(上)
- Android从零开搞系列:自定义View(7)ScrollTo+ScrollBy+Scroller+NestedScrolling机制(下)
- Android View Scroller类,scrollTo(...)和scrollBy(...)方法
- Android View scrollTo scrollBy
- View 的滑动实现之二(ScrollTo,ScrollBy和Scroller)
- View的scrollTo(),scrollBy()以及Scroller,OverScroller
- Android scrollTo() scrollBy() Scroller讲解及应用
- Android scrollTo() scrollBy() scroller 学习总结
- Android Scroller入门(一)之ScrollTo、ScrollBy
- Android scrollTo() scrollBy() Scroller讲解及应用
- Android scrollTo() scrollBy() Scroller讲解及应用
- View移动(scrollTo()、scrollBy()方法)
- [Android] View scrollTo()与scrollBy()
- 总结Scroller ScrollTo ScrollBy
- View滑动的原理,解析scrollTo,ScrollBy和Scroller
- Scroller、scrollTo、ScrollBy学习笔记
- Android View 的scrollTo 和 scrollBy方法
- android View的ScrollBy ScrollTo getScrollX getScrollY
- magento 的后台缓存机制
- Spring filter 字符串过滤器
- 数据库部分1
- webstorm下vuejs开发配置
- Aria2 百度网盘下载教程
- Android从零开搞系列:自定义View(6)ScrollTo+ScrollBy+Scroller+NestedScrolling机制(上)
- 动力节点——构造代码块(十一)
- ARM处理器工作模式
- 【javaEE】mybatis下编译出错
- Bootstrap源码解读(第十一弹:模态弹出框)
- Windows TrayIcon (Shell_NotifyIcon)
- magento的prototype表单验证
- linux命令
- 方法区和运行时常量池溢出