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 ...
随机推荐
- pie.htc 在IE下不起作用~~~
一直用的IE11 然后选择其中的兼容模式来测试IE 7~10的情况. 最近由于客户要求 圆角阴影兼容IE,只能选择PIE.HTC的方案. 但是反复测试发现不起作用. 官方文档的几种说明: 1. pie ...
- 基于Cef内核的多店铺登录器(含源码)
公司是做电商的,在速卖通平台上开了若干店铺,每天都需要登录店铺打理,如:发货提交.获取运单号等.多个店铺的情况下,同时使用浏览器就会非常繁琐,如:要记住帐户名和密码,还要在不同店铺间切换.如果能够制作 ...
- C#中的DBNull、Null、""和String.Empty
1.对DBNull的解释: 该类用于指示不存在某个已知值(通常在数据库应用程序中). 在数据库应用程序中,空对象是字段的有效值.该类区分空值(空对象)和未初始化值(DBNull.Va ...
- C#设计模式之十五命令模式(Command Pattern)【行为型】
一.引言 今天我们开始讲"行为型"设计模式的第二个模式,该模式是[命令模式],又称为行动(Action)模式或交易(Transaction)模式,英文名称是:Command P ...
- RunLoop已入门?赶紧来应用一下
前言 对RunLoop还没有什么概念的同学请移步我的上一篇文章,传送门:RunLoop入门 看我就够了http://www.cnblogs.com/weiming4219/p/7879443.html ...
- canvas动画3:交互
canvas动画3 时隔很久,本人终于又写博客了(重度拖延症),把之前留下的canvas交互动画讲一讲. 电脑上的交互,指的是鼠标和键盘,我们今天主要用的是鼠标. 既然是鼠标的话,就要获取鼠标的各种事 ...
- bootstrap 组件之"导航条"
一个典型的导航条基本代码如下: <nav class="navbar navbar-default"> <div class="container&qu ...
- C# tostring
GUID: 即Globally Unique Identifier(全球唯一标识符) 也称作 UUID(Universally Unique IDentifier) . GUID是一个通过特定算法产生 ...
- EntityFramework For Mysql 动态切换数据源
1.简介 在工作中遇到一个问题.项目有三个数据库(三个数据库表结构一样),用户可以选择使用哪个数据库.其实就是动态切换数据库连接. 2.EntityFramework For Mysql 先来简单的介 ...
- 【原创】python实现清理本地缓存垃圾
#coding=utf-8 import os import glob try: #利用glob模块定位需要清理垃圾的模糊路径 File_1 = glob.glob("C:\Windows\ ...