Android View视图系统分析和Scroller和OverScroller分析
Android View视图系统分析和Scroller和OverScroller分析
View 视图分析
而ViewGroup也是对于View的一种实现。所以说全部的View元素在根本上都是一样的。当然这并不等于说View == ViewGroup,就好比仅仅有ViewGroup才可以addView。
当然,假设你不是非常理解也不是非常致命的问题。以下我会做一些解释。
同理,这也就解释了我们队Canvas採取translate(平移)、clipRect(剪切)一系列变换的意义所在。那么Canvas没有边界。是不是就意味着我们的View资源一定都能如我们所愿吗。
Canvas是没有边界的,可是我们的Layout区域确实有边界的。假设,我们希望看到我们的View子元素,那么他就必须在我们的视图坐标(可视区域),可是在此处还要注意Layout区域并不一定都可见。
我相信在你第一眼看到这张图片的时候你就能够瞬间的对于Layout坐标(视图区域)有了一个认识了。没错,你所示那些蓝角红线组成的长方形区域就是我们的布局区域,那么他们的框定是源自于哪里呢。
这里还记得我上面强调过的
LastCallMessageContainer.layout(left, top, left+ LastCallMessageContainer.getWidth(), top+ LastCallMessageContainer.getHeight());
这样的方式来实现尾随手指移动的View。可是这样的方式好不好呢。答案非常明显,并不好,有机会的话给打击分享一下实现方式吧。
scrollTo()和scrollBy()分析
scrollTo()和scrollBy()分析
在View.java中提供了了例如以下两个变量以及对应的属性方法去读取滚动值 ,例如以下: View.java类中
- /**
- * The offset, in pixels, by which the content of this view is scrolled
- * horizontally.
- * {@hide}
- */
- protected int mScrollX; //该视图内容相当于视图起始坐标Layout的偏移量 , X轴 方向
- /**
- * The offset, in pixels, by which the content of this view is scrolled
- * vertically.
- * {@hide}
- */
- protected int mScrollY; //该视图内容相当于视图起始坐标Layout的偏移量 , Y轴方向
- /**
- * Return the scrolled left position of this view. This is the left edge of
- * the displayed part of your view. You do not need to draw any pixels
- * farther left, since those are outside of the frame of your view on
- * screen.
- *
- * @return The left edge of the displayed part of your view, in pixels.
- */
- public final int getScrollX() {
- return mScrollX;
- }
- /**
- * Return the scrolled top position of this view. This is the top edge of
- * the displayed part of your view. You do not need to draw any pixels above
- * it, since those are outside of the frame of your view on screen.
- *
- * @return The top edge of the displayed part of your view, in pixels.
- */
- public final int getScrollY() {
- return mScrollY;
- }
Word后面的图案是TextView的背景。
public void scrollTo(int x, int y)
说明:在当前视图内容偏移至(x , y)坐标处,即位于Layout区域(x , y)坐标处。
方法原型为: View.java类中
- /**
- * 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
- */
- public void scrollTo(int x, int y) {
- //偏移位置发生了改变
- if (mScrollX != x || mScrollY != y) {
- int oldX = mScrollX;
- int oldY = mScrollY;
- mScrollX = x; //赋新值,保存当前廉价量
- mScrollY = y;
- //回调onScrollChanged方法
- onScrollChanged(mScrollX, mScrollY, oldX, oldY);
- if (!awakenScrollBars()) {
- invalidate(); //一般都引起重绘
- }
- }
- }
public void scrollBy(int x, int y)
说明:在当前视图内容在Layout布局中继续偏移(x , y)个单位。
方法原型为: View.java类中
- /**
- * 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
- */
- // 看出原因了吧 。
。
mScrollX 与 mScrollY 代表我们当前偏移的位置 , 在当前位置继续偏移(x ,y)个单位
- public void scrollBy(int x, int y) {
- scrollTo(mScrollX + x, mScrollY + y);
- }
大家自己想一想。
Scroller 和OverScroller分析
我们知道想把一个View的内容偏移至指定坐标(x,y)处,利用scrollTo()方法直接调用就OK了。但我们不能忽视的是,该方法本身来的的副作用:很迅速的将View/ViewGroup偏移至目标点,而没有对这个偏移过程有不论什么控制。对用户而言可能是不太友好的。于是,基于这样的偏移控制,Scroller类被设计出来了,该类的主要作用是为偏移过程制定一定的控制流程(后面我们会知道的很多其它),从而使偏移更流畅,更完美。
可能上面说的比較悬乎,道理也没有讲透。以下我就依据特定情景帮助大家分析下:
情景: 从上海怎样到武汉?
普通的人可能会想,so easy : 飞机、轮船、11路公交车...
文艺的人可能会想, 小 case : 时空忍术(火影的招数)、翻个筋斗(孙大圣的招数)...
无论怎么样,我们想出来的套路可能有两种:
1、有个时间控制过程才干抵达(缓慢的前进) ----- 相应于Scroller的作用
如果做火车,这个过程可能包含: 火车速率,花费周期等。
2、瞬间移动(超神太快了。都眩晕了,用户体验不太好) ------ 相应于scrollTo()的作用
我们看看View里面的computeScroll()做了些什么
/**
* Called by a parent to request that a child update its values for mScrollX
* and mScrollY if necessary. This will typically be done if the child is
* animating a scroll using a {@link android.widget.Scroller Scroller}
* object.
*/
public void computeScroll() {
}
空的。意思非常明显。自己加入。
computeScroll()方法介绍
为了易于控制滑屏控制,Android框架提供了 computeScroll()方法去控制这个流程。在绘制View时。会在draw()过程调用该方法。因此。 再配合使用Scroller实例。我们就能够获得当前应该的偏移坐标,手动使View/ViewGroup偏移至该处。
computeScroll()方法原型例如以下,该方法位于ViewGroup.java类中
- /**
- * Called by a parent to request that a child update its values for mScrollX
- * and mScrollY if necessary. This will typically be done if the child is
- * animating a scroll using a {@link android.widget.Scroller Scroller}
- * object.
- */由父视图调用用来请求子视图依据偏移值 mScrollX,mScrollY又一次绘制
- public void computeScroll() { //空方法 。自己定义ViewGroup必须实现方法体
- }
为了实现偏移控制,一般自己定义View/ViewGroup都须要重载该方法 。
其调用过程位于View绘制流程draw()过程中,例如以下:
- @Override
- protected void dispatchDraw(Canvas canvas){
- ...
- for (int i = 0; i < count; i++) {
- final View child = children[getChildDrawingOrder(count, i)];
- if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
- more |= drawChild(canvas, child, drawingTime);
- }
- }
- }
- protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
- ...
- child.computeScroll();
- ...
- }
既然如今我们知道了:
其实讲到这里,有的同学可能比較迷惑,OverScroller和Scroller有什么差别呢?其实,这两个类都属于Scrollers,Scroller出现的比較早,在API1就有了。OverScroller是在API9才加入上的,出现的比較晚,所以功能比較完好,Over的意思就是超出。即OverScroller提供了对超出滑动边界的情况的处理,这两个类80%的API是一致的。OverScroller比Scroller加入了一下几个方法
☞ isOverScrolled()
☞ springBack(int startX, int startY, int minX, int maxX, int minY, int maxY)
☞ fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, int overX, int overY)
☞ notifyHorizontalEdgeReached(int startX, int finalX, int overX)
☞ notifyVerticalEdgeReached(int startY, int finalY, int overY)
从名字也能看出来。都是对Over功能的支持。其它的API都一样。所以介绍通用API的时候。并不区分OverScroller和Scroller。
以下简介一下经常使用的API。
☞ startScroll(int startX, int startY, int dx,
int dy)
☞ startScroll(int
startX, int startY, int dx, int dy,int duration)
核心用来开启滚动的方法:
參数
startX 滚动起始值
startY 滚动起始值
dx 水平方向滑动的距离,正值会使滚动向左滚动
dy 垂直方向滑动的距离。正值会使滚动向上滚动
duration 滚动持续时间,以毫秒计。缺省值250ms作为持续时间。
☞ computeScrollOffset() 这个函数非常核心,表面上来看他仅仅是用来推断我们的滚动是否结束
if (mScroller.computeScrollOffset())
看起来似乎没有什么价值,起始不然
//依据当前已经消逝的时间计算当前的坐标点,保存在mCurrX和mCurrY值中
public boolean computeScrollOffset() {
if (mFinished) { //已经完毕了本次动画控制,直接返回为false
return false;
}
.......
mScrollerX.updateScroll(q);
mScrollerY.updateScroll(q);
.......
}
这就是为什么我们称Scroller为滚动的助手类,原来如此,我们在startScroll中设好初始值 、滚动距离、滚动时间。那么
computeScrollOffset会帮我们计算出在特定的时间内应该滚动在什么地方,到时候我们仅仅要通过getCurrX()和getCurrY()得到就能够了
☞ getCurrX() 这个就是获取当前滑动的坐标值,由于Scrollers仅仅是一个辅助计算类,所以假设我们想获取滑动时的时时坐标,就能够通过这种方法获得。然后在computeScroll()里面调用
☞ getFinalX() 这个是用来获取终于滑动停止时的坐标
☞ isFinished() 用来推断当前滚动是否结束
那么 。到了这里我们就一目了然。Scroller的基本用法不外乎:
mScroller.startScroll(<span style="color: rgb(51, 51, 51); font-family: 宋体;font-size:18px; line-height: 30px; text-indent: 28px;">startX ,<span style="color: rgb(51, 51, 51); font-family: 宋体;font-size:18px; line-height: 30px; text-indent: 28px;">startY,dx,dy,duration</span></span>);
@Override
public void computeScroll() { // 先推断mScroller滚动是否完毕
if (mScroller.computeScrollOffset()) {
// 这里调用View的scrollTo()完毕实际的滚动
scrollTo( mScroller.getCurrX(), mScroller .getCurrY());
// 必须调用该方法,否则不一定能看到滚动效果
invalidate();
}
super.computeScroll();
}
那么到了这里,基本上我们对于Scroller的基本使用应该就不是问题了。
今天就到这里吧。下次再写个高于高级使用续篇吧。
Android View视图系统分析和Scroller和OverScroller分析的更多相关文章
- Android View坐标Left, Right, Top, Bottom
Android View坐标Left, Right, Top, Bottom 1.分析说明Left, Right, Top, Bottom View中对于该字段说明如下,相对父布局的的位置 相对父布局 ...
- Android View 的添加绘制流程 (二)
概述 上一篇 Android DecorView 与 Activity 绑定原理分析 分析了在调用 setContentView 之后,DecorView 是如何与 activity 关联在一起的,最 ...
- 手势识别官方教程(4)在挑划或拖动手势后view的滚动用ScrollView和 HorizontalScrollView,自定义用Scroller或OverScroller
简单滚动用ScrollView和 HorizontalScrollView就够.自定义view时可能要自定义滚动效果,可以使用 Scroller或 OverScroller Animating a S ...
- Android列表视图(List View)
Android列表视图(ListView) ListView是一个显示滚动项列表的示视图组(viewgroup),通过使用适配器(Adapter)把这些列表项自动插入到列表中.适配器比如从一个数组或是 ...
- android2.3 View视图框架源码分析之一:android是如何创建一个view的?
View是所有控件的一个基类,无论是布局(Layout),还是控件(Widget)都是继承自View类.只不过layout是一个特殊的view,它里面创建一个view的数组可以包含其他的view而已. ...
- Android 它们的定义View视图
创建一个新视图将满足我们独特UI需求. 本文介绍的发展将指南针罗盘接口使用UI,通过继承View定义自己的视图类工具,为了深入了解自己的自定义视图. 实现效果图: 源码: 布局文件activity_m ...
- Android View体系(一)视图坐标系
前言 Android View体系是界面编程的核心,他的重要性不亚于Android四大组件,在这个系列中我会陆续讲到View坐标系.View的滑动.View的事件分发等文章来逐步介绍Android V ...
- Android View体系(四)从源码解析Scroller
在Android View体系(二)实现View滑动的六种方法这篇文章中我们讲到了用Scroller来实现View的滑动,所以这篇文章我们就不介绍Scroller是如何使用的了,本篇就从源码来分析下S ...
- Android的视图(View)组件
Android的绝大部分UI组件都放在android.widget包及其子包.android,view包及其子包中,Android应用的所有UI组件都继承了View类,View组件非常类似于Swing ...
随机推荐
- 一个简单的MVC框架的实现-基于注解的实现
1.@Action注解声明 package com.togogo.webtoservice.annotations; import java.lang.annotation.Documented; i ...
- 移动端1px 边框完整方案(四个方向)
使用stylus(预处理) 需要一个函数接收两个参数 第一个需要在哪个方向出现边框 第二个边框颜色 $border1px(face,$color) 根据传入的方向属性,调整其他参数 l 左右方向 t ...
- 1045-access denied for user 'root'@
在用sqlyog图形界面远程登录阿里云mysql数据库的时候出现了如下的问题, 1045-access denied for user 'root'@ 刚开始以为阿里云esc的安全组并没有配置3306 ...
- 532. K-diff Pairs in an Array
Given an array of integers and an integer k, you need to find the number of unique k-diff pairs in t ...
- 网页加速特技之 AMP
据统计,40%的人会放弃使用加载时间超过3秒的网站.对于加载慢的页面我也是没耐心等待的,同类型网站那么多,为什么不选择加载速度更快体验更好的呢.为了解决网页加载慢的问题,Google联合数十家技术机构 ...
- java 压缩导出多个excel
简单介绍下我实现的功能,首先是我的excel上传,它是以blob字段存储在oracel数据库中的,我实现的是循环遍历blob字段并使用io流进行打包下载,如有需要可自行修改 使用技术有,springM ...
- springboot整合shiro
请大家在看本文之前,先了解如下知识点: 1.Shiro 是什么?怎么用? 2.Cas 是什么?怎么用? 3.最好有Spring基础 可以先看看这两篇文章,按照这2篇文章的内容做一遍: Spring B ...
- mac 安装protobuf,并编译
因公司接口协议是PB文件,需要将 PB 编译成JAVA文件,且MAC 电脑,故整理并分享MAC安装 google 下的protobuf 文件 MAC 安装protobuf 流程 1.下载 http ...
- 苹果快速的修复了Mac OS High Sierra 上出现了root的漏洞
最近苹果因为Mac最新系统 Mac OS High Sierra 上出现了root的漏洞走上了风口浪尖,不过还好,在一封苹果给科技媒体'9to5 Mac'的回复中得知,苹果在接收到报告之后,立即展开修 ...
- IntelliJ IDEA(二) :面板介绍
一.面板说明 IDEA面板的全貌如下图 二.菜单栏 下面会简单介绍下一些常用的部分菜单使用,如有疑问或补充欢迎留言. (1).File文件 1. New:新建一个工程 可以新建project,导入已存 ...