关于View绘制系列的文章已经完成了四篇了,前面四篇文章主要带小伙伴们熟悉一下View的体系的整体框架、View的测量以及布局等过程,从本篇博客开始,我们就来看看View的绘制过程。View的绘制涉及到许多细小的知识点,一篇博客很难全部介绍清楚,所以我打算采用农村包围城市的方式,先把这里边会涉及到的各种琐碎的知识点给小伙伴们介绍一遍,然后我们再来看View绘制的整体流程,及draw方法和onDraw方法到底是怎么回事。OK,那么本篇博客我们就先来看看View绘制过程中涉及到的第一个问题,View的滚动。对了,如果小伙伴们还没看过之前的四篇文章,可以先移步这里,那四篇文章有助于你理解本文:

1.View绘制详解,从LayoutInflater谈起

2.View绘制详解(二),从setContentView谈起

3.View绘制详解(三),扒一扒View的测量过程

4.View绘制详解(四),谝一谝layout过程

好了,废话不多说,来看看今天的话题。

OK,说到View的绘制,我们首先得明白一点,就是我们Android手机中View是没有边界的,View是无限大的,View中的画布Canvas也是无限大的。说到这里有许多小伙伴就有疑问了,我们前面不是刚说了View的测量吗?每一个View都是有大小的,怎么现在又没有大小了呢?其实,我们说的View的大小是指View的父容器分配给它的大小,View的内容只能在父容器分配的大小中显示,如果View的内容显示在父容器分配的区域之外,则用户就看不到这一部分内容,但是并不是说超过的部分就不存在。我们以下图的TextView为例:

TextView显示在任意一个容器中,该容器分配给TextView的大小就是中间黑色框的部分,TextView在绘制它自身的内容的时候只能在中间黑色框中绘制,绘制在黑色框以外的部分将会显示不出来,但并不能意味着这不能绘制。我们在onDraw方法中获取到的canvas,它的大小经过剪裁之后已经是当前控件的大小了,同时,参考的坐标点也变成了当前View的左上角。

OK,为什么要说这个问题呢?因为这里涉及到View绘制时的两个方法ScrollTo和ScrollBy,我们来看看View中draw方法的一小段源码:

@CallSuper
public void draw(Canvas canvas) { ...
... if (!dirtyOpaque) {
drawBackground(canvas);
} ...
...
} private void drawBackground(Canvas canvas) { ...
... final int scrollX = mScrollX;
final int scrollY = mScrollY;
if ((scrollX | scrollY) == 0) {
background.draw(canvas);
} else {
canvas.translate(scrollX, scrollY);
background.draw(canvas);
canvas.translate(-scrollX, -scrollY);
}
}

这个是绘制View的背景的一段源码,在View绘制之前,要先将canvas平移,平移完了之后再绘制,绘制完了之后再平移成原来的状态。为什么要这么做呢?我们来看下面一张图:

父容器分配给TextView可显示的区域就是中间的黑色框,但是TextView的内容区域由于滚动已经不处于这个黑色框中了(辛弃疾的词即为TextView的内容区域),那怎么样完成这种滚动效果呢?我们需要通过translate方法来让canvas平移。小伙伴们想象一下,中间的黑色框不动,画布向右下平移才能进入到黑色框中,移到黑色框中之后进行绘制,绘制完成之后再移动回去,这个时候TextView的内容区域不就跑到TextView的左上角去了么。那么在这次的移动操作中,我们的scrollX和scrollY两个参数为正数,但是我们的View的内容却往左上角移动,这就是原因。因为我们移动的不是TextView,我们移动的是canvas。我们来看下面一个简单的例子,效果图如下:

当我点击Button时,TextView的内容自动移动到TextView的左下角,我们来看看Button的点击事件:

tv.scrollTo(-100, -100);

负数是向右下角移动,因为负数表示canvas先向左上角x、y轴各移动100px,然后再向右下角x、y各100px,如下:

说到这里,实名反对泡网这篇文章,View 的scrollTo 和scrollBy,误人子弟。

OK,对于一个View而言,scrollTo移动的是View的内容,对于ViewGroup而言,scrollTo移动的则是ViewGroup中的子控件。OK,我们来看看scrollTo的源码:

public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}

这里就是给mScrollX和mScrollY重新赋值,然会回调onScrollChangeListener重新绘制View。OK,有一个和scrollTo功能相似的方法叫做ScrollBy,我们来看看:

public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}

scrollBy中也是调用了scrollTo发那个发,不同的是它没有给mScrollX和mScrollY重新赋值,而是在当前的基础上再偏移多少。这也就是我们常说的scrollTo表示移动到哪里,而scrollBy表示移动多少。OK,基于此,我们来做下面一个小案例:

屏幕中有一个TextView,当我的手指在TextView上拖动的时候,我们的TextView可以自由的移动,OK,我们来看看代码:

tv.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = (int) event.getX();
downY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
((ViewGroup) v.getParent()).scrollBy(-(int) event.getX()+downX, -(int) event.getY()+downY);
break;
}
return true;
}
});

TextView想在它自己所在的容器中滚动,但是TextView自己不能滚动,如果调用了TextView的滚动方法实际上滚动的就是TextView中的文本了。所以我们要调用的是TextView的父容器的滚动方法,而且还要将值改为相反数,原因不用我多说了吧。至于要加上downX和downY两个值,是因为我们的手指不一定就按在TextView的左上角,所以要减去手指到TextView左上角这一段距离。

OK,这就是View绘制方法中涉及到的第一个小细节(View无限大,canvas无限大),以及由这个细节牵扯出来的两个方法scrollTo和scrollBy。OK,draw方法的第一次分析就到这里,有问题欢迎留言讨论。

以上。

View绘制详解(五),draw方法细节详解之View的滚动/滑动问题的更多相关文章

  1. Android View 绘制流程(Draw) 完全解析

    前言 前几篇文章,笔者分别讲述了DecorView,measure,layout流程等,接下来将详细分析三大工作流程的最后一个流程——绘制流程.测量流程决定了View的大小,布局流程决定了View的位 ...

  2. Android应用层View绘制流程之measure,layout,draw三步曲

    概述 上一篇博文对DecorView和ViewRootImpl的关系进行了剖析,这篇文章主要是来剖析View绘制的三个基本流程:measure,layout,draw.仅仅有把这三个基本流程搞清楚了, ...

  3. Android应用层View绘制流程与源码分析

    1  背景 还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原 ...

  4. 【view绘制流程】理解

    一.概述 View的绘制是从上往下一层层迭代下来的.DecorView-->ViewGroup(--->ViewGroup)-->View ,按照这个流程从上往下,依次measure ...

  5. 【朝花夕拾】Android自定义View篇之(一)View绘制流程

    前言 转载请申明转自[https://www.cnblogs.com/andy-songwei/p/10955062.html]谢谢! 自定义View.多线程.网络,被认为是Android开发者必须牢 ...

  6. 从Android源码分析View绘制

    在开发过程中,我们常常会来自定义View.它是用户交互组件的基本组成部分,负责展示图像和处理事件,通常被当做自定义组件的基类继承.那么今天就通过源码来仔细分析一下View是如何被创建以及在绘制过程中发 ...

  7. Android 使用View绘制文字(DrawText)技术总结

    转载请注明出处: http://www.cnblogs.com/renhui/p/7453534.html 这里的绘制文字不是直接调用TextView.setText(String content)去 ...

  8. Android笔记--View绘制流程源码分析(二)

    Android笔记--View绘制流程源码分析二 通过上一篇View绘制流程源码分析一可以知晓整个绘制流程之前,在activity启动过程中: Window的建立(activit.attach生成), ...

  9. android自定义View绘制天气温度曲线

    原文:android自定义View绘制天气温度曲线 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u012942410/article/detail ...

随机推荐

  1. 在window server 2008 64位系统上 发布网站的过程中遇到的问题

    发布网站的过程如下: 1.安装数据库系统2.建立数据库,执行sql3.安装iis4.在本地机子上发布网站5.把发布好的东西拷贝到IIS上 1.安装数据库系统: 出现错误:必须使用角色管理工具 安装或配 ...

  2. Apache Rewrite常用设置说明

    例子: RewriteEngine on 打开引擎 RewriteRule test.html /test.php [L] RewriteRule test.html?$ /tianqi.php?s1 ...

  3. java开发者最常去的20个英文网站

    java开发者最常去的20个英文网站: 1.[http://www.javaalmanac.com] Java开发者年鉴一书的在线版本. 要想快速查到某种Java技巧的用法及示例代码, 这是一个不错的 ...

  4. Hadoop在百度的应用

    百度作为全球最大的中文搜索引擎公司,提供基于搜索引擎的各种产品,包括以网络搜索为主的功能性搜索:以贴吧为主的社区搜索:针对区域.行业的垂直搜索.MP3音乐搜索,以及百科等,几乎覆盖了中文网络世界中所有 ...

  5. 15个顶级Java多线程面试题及答案

    1)现在有T1.T2.T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行? 这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟悉.这个多线程问题比 ...

  6. Java Thread.interrupt 害人! 中断JAVA线程(zz)

    http://www.blogjava.net/jinfeng_wang/archive/2012/04/22/196477.html#376322 ————————————————————————— ...

  7. MongoDB的update有关问题(JAVA)——如何一次更新所有的相同记录

    MongoDB的update问题(JAVA)——怎么一次更新所有的相同记录用如下这个函数:public WriteResult update(DBObject q,  DBObject o,  boo ...

  8. 最大流&最小割 - 专题练习

    [例1][hdu5889] - 算法结合(BFS+Dinic) 题意 \(N\)个点\(M\)条路径,每条路径长度为\(1\),敌人从\(M\)节点点要进攻\(1\)节点,敌人总是选择最优路径即最短路 ...

  9. ElasticSearch中文分词(IK)

    ElasticSearch常用的很受欢迎的是IK,这里稍微介绍下安装过程及测试过程.   1.ElasticSearch官方分词 自带的中文分词器很弱,可以体检下: [zsz@VS-zsz ~]$ c ...

  10. jdbc线程池

    连接oracle数据库的jdbc线程池 首先建立一个properties类型的文件存放一些信息:jdbc.properties driverClassName=oracle.jdbc.driver.O ...