当前位置:首页 » 安卓系统 » androidview

androidview

发布时间: 2024-09-15 12:51:01

Ⅰ Android UI绘制之View绘制的工作原理

这是AndroidUI绘制流程分析的第二篇文章,主要分析界面中View是如何绘制到界面上的具体过程。

ViewRoot 对应于 ViewRootImpl 类,它是连接 WindowManager 和 DecorView 的纽带,View的三大流程均是通过 ViewRoot 来完成的。在 ActivityThread 中,当 Activity 对象被创建完毕后,会将 DecorView 添加到 Window 中,同时会创建 ViewRootImpl 对象,并将 ViewRootImpl 对象和 DecorView 建立关联。

measure 过程决定了 View 的宽/高, Measure 完成以后,可以通过 getMeasuredWidth 和 getMeasuredHeight 方法来获取 View 测量后的宽/高,在几乎所有的情况下,它等同于View的最终的宽/高,但是特殊情况除外。 Layout 过程决定了 View 的四个顶点的坐标和实际的宽/高,完成以后,可以通过 getTop、getBottom、getLeft 和 getRight 来拿到View的四个顶点的位置,可以通过 getWidth 和 getHeight 方法拿到View的最终宽/高。 Draw 过程决定了 View 的显示,只有 draw 方法完成后 View 的内容才能呈现在屏幕上。

DecorView 作为顶级 View ,一般情况下,它内部会包含一个竖直方向的 LinearLayout ,在这个 LinearLayout 里面有上下两个部分,上面是标题栏,下面是内容栏。在Activity中,我们通过 setContentView 所设置的布局文件其实就是被加到内容栏中的,而内容栏id为 content 。可以通过下面方法得到 content:ViewGroup content = findViewById(R.android.id.content) 。通过 content.getChildAt(0) 可以得到设置的 view 。 DecorView 其实是一个 FrameLayout , View 层的事件都先经过 DecorView ,然后才传递给我们的 View 。

MeasureSpec 代表一个32位的int值,高2位代表 SpecMode ,低30位代表 SpecSize , SpecMode 是指测量模式,而 SpecSize 是指在某种测量模式下的规格大小。
SpecMode 有三类,如下所示:

UNSPECIFIED

EXACTLY

AT_MOST

LayoutParams需要和父容器一起才能决定View的MeasureSpec,从而进一步决定View的宽/高。

对于顶级View,即DecorView和普通View来说,MeasureSpec的转换过程略有不同。对于DecorView,其MeasureSpec由窗口的尺寸和其自身的LayoutParams共同确定;

对于普通View,其MeasureSpec由父容器的MeasureSpec和自身的Layoutparams共同决定;

MeasureSpec一旦确定,onMeasure就可以确定View的测量宽/高。

小结一下

当子 View 的宽高采用 wrap_content 时,不管父容器的模式是精确模式还是最大模式,子 View 的模式总是最大模式+父容器的剩余空间。

View 的工作流程主要是指 measure 、 layout 、 draw 三大流程,即测量、布局、绘制。其中 measure 确定 View 的测量宽/高, layout 确定 view 的最终宽/高和四个顶点的位置,而 draw 则将 View 绘制在屏幕上。

measure 过程要分情况,如果只是一个原始的 view ,则通过 measure 方法就完成了其测量过程,如果是一个 ViewGroup ,除了完成自己的测量过程外,还会遍历调用所有子元素的 measure 方法,各个子元素再递归去执行这个流程。

如果是一个原始的 View,那么通过 measure 方法就完成了测量过程,在 measure 方法中会去调用 View 的 onMeasure 方法,View 类里面定义了 onMeasure 方法的默认实现:

先看一下 getSuggestedMinimumWidth 和 getSuggestedMinimumHeight 方法的源码

可以看到, getMinimumWidth 方法获取的是 Drawable 的原始宽度。如果存在原始宽度(即满足 intrinsicWidth > 0),那么直接返回原始宽度即可;如果不存在原始宽度(即不满足 intrinsicWidth > 0),那么就返回 0。

接着看最重要的 getDefaultSize 方法:

如果 specMode 为 MeasureSpec.UNSPECIFIED 即未指定模式,那么返回由方法参数传递过来的尺寸作为 View 的测量宽度和高度;
如果 specMode 不是 MeasureSpec.UNSPECIFIED 即是最大模式或者精确模式,那么返回从 measureSpec 中取出的 specSize 作为 View 测量后的宽度和高度。

看一下刚才的表格:

当 specMode 为 EXACTLY 或者 AT_MOST 时,View 的布局参数为 wrap_content 或者 match_parent 时,给 View 的 specSize 都是 parentSize 。这会比建议的最小宽高要大。这是不符合我们的预期的。因为我们给 View 设置 wrap_content 是希望View的大小刚好可以包裹它的内容。

因此:

如果是一个 ViewGroup,除了完成自己的 measure 过程以外,还会遍历去调用所有子元素的 measure 方法,各个子元素再递归去执行 measure 过程。

ViewGroup 并没有重写 View 的 onMeasure 方法,但是它提供了 measureChildren、measureChild、measureChildWithMargins 这几个方法专门用于测量子元素。

如果是 View 的话,那么在它的 layout 方法中就确定了自身的位置(具体来说是通过 setFrame 方法来设定 View 的四个顶点的位置,即初始化 mLeft , mRight , mTop , mBottom 这四个值), layout 过程就结束了。

如果是 ViewGroup 的话,那么在它的 layout 方法中只是确定了 ViewGroup 自身的位置,要确定子元素的位置,就需要重写 onLayout 方法;在 onLayout 方法中,会调用子元素的 layout 方法,子元素在它的 layout 方法中确定自己的位置,这样一层一层地传递下去完成整个 View 树的 layout 过程。

layout 方法的作用是确定 View 本身的位置,即设定 View 的四个顶点的位置,这样就确定了 View 在父容器中的位置;
onLayout 方法的作用是父容器确定子元素的位置,这个方法在 View 中是空实现,因为 View 没有子元素了,在 ViewGroup 中则进行抽象化,它的子类必须实现这个方法。

1.绘制背景( background.draw(canvas); );
2.绘制自己( onDraw );
3.绘制 children( dispatchDraw(canvas) );
4.绘制装饰( onDrawScrollBars )。

dispatchDraw 方法的调用是在 onDraw 方法之后,也就是说,总是先绘制自己再绘制子 View 。

对于 View 类来说, dispatchDraw 方法是空实现的,对于 ViewGroup 类来说, dispatchDraw 方法是有具体实现的。

通过 dispatchDraw 来传递的。 dispatchDraw 会遍历调用子元素的 draw 方法,如此 draw 事件就一层一层传递了下去。dispatchDraw 在 View 类中是空实现的,在 ViewGroup 类中是真正实现的。

如果一个 View 不需要绘制任何内容,那么就设置这个标记为 true,系统会进行进一步的优化。

当创建的自定义控件继承于 ViewGroup 并且不具备绘制功能时,就可以开启这个标记,便于系统进行后续的优化;当明确知道一个 ViewGroup 需要通过 onDraw 绘制内容时,需要关闭这个标记。

参考:《Android开发艺术探索》

Ⅱ Android中View,SurfaceView的绘图和GLSurfaceView绘图有区别吗

Android游戏当中主要的除了控制类外就是显示类View。SurfaceView是从View基类中派生出来的显示类。android游戏开发中常用的三种视图是:
view、SurfaceView和GLSurfaceView的区别如下:
View:显示视图,内置画布,提供图形绘制函数、触屏事件、按键事件函数等;必须在UI主线程内更新画面,速度较慢。
SurfaceView:基于view视图进行拓展的视图类,更适合2D游戏的开发;是view的子类,类似使用双缓机制,在新的线程中更新画面所以刷新界面速度比view快。
GLSurfaceView:基于SurfaceView视图再次进行拓展的视图类,专用于3D游戏开发的视图;是SurfaceView的子类,openGL专用。
在2D游戏开发中,大致可以分为两种游戏框架,View和SurfaceView。
View和SurfaceView区别:
View:必须在UI的主线程中更新画面,用于被动更新画面。
surfaceView:UI线程和子线程中都可以。在一个新启动的线程中重新绘制画面,主动更新画面。
UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。
当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步,涉及到线程同步。
所以基于以上,根据游戏特点,一般分成两类。
1 被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。
2 主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。

Ⅲ Android中View的创建过程

我们知道在onCreate里面View还是没有测绘完成的。那么什么时候测绘完成了?答案是onResume。
通过查看源码 我们可以看到在onCreate方法里面调用了getWindow()方法然后在将我们的页面塞到这个window里面。这个window也就是PhonwWindow.

那PhoneWindow是什么时候被创建的?
这就引出了Activity的创建流程。
那Activity是怎么被创建的呢?
由于Activity是一个组件他是由系统使用 ActivityThread 方法去创建的。
现在我来分析下:
先来到ActivityThread类的handleLaunchActivity方法。

可以看到他去调用了Activity的performCreate方法。

现在我们终于看到onCreate方法被调用了。

这里还有个重点,在performLaunchActivity里面去调用Activity的onCreate方法之前还去做了一件很重要的事情,这个事情在第3224行:调用了Activity的attach方法。

现在跟到Activity的attach方法:找到了我们一直找的PhoneWindow的创建。

Ⅳ Android基础学习-View概述

在Android应用开发中,View是构建用户界面的核心组件,它是所有控件的基类,可以理解为UI界面中的矩形区域,比如TextView、Button、ImageView等基本控件,以及能容纳多个View的容器,如LinearLayout、RelativeLayout、ListView、RecyclerView等,它们共同构成了Android的视图层次结构。

View的位置和大小通过四个顶点坐标决定,这些坐标对应于getLeft(), getRight(), getTop(), 和 getBottom() 方法,进而可以计算出宽度(right - left)和高度(bottom - top)。理解并设置好这些属性,能精确控制控件在屏幕上的布局。

View与用户的交互主要通过MotionEvent事件来实现,当手指接触屏幕时,会触发ACTION_DOWN,手指移动则触发ACTION_MOVE,手指离开屏幕则为ACTION_UP。通过设置onTouch事件,可以捕获并响应这些动作,为用户提供丰富的交互体验。

在Android中,View的表示方式有两种:一是通过XML布局文件,比如在一个垂直排列的LinearLayout中,你可以放置一个TextView和一个Button。二是通过Java代码动态创建和管理,例如创建一个LinearLayout,设置其子控件方向为垂直,然后添加文本框和按钮实例。这两种方法都可以达到相同的效果,开发者可以根据项目需求灵活选择。

View是UI设计的基础,无论是简单的文本显示还是复杂的交互界面,都离不开View的构建。后续的内容将深入探讨更多View控件及其自定义方法,敬请关注。

热点内容
用户管理源码 发布:2024-11-24 21:29:36 浏览:677
监控怎么配置路由器 发布:2024-11-24 21:29:27 浏览:455
小型编译器的实现 发布:2024-11-24 21:27:48 浏览:999
安卓手机为什么下巴不掉 发布:2024-11-24 21:26:37 浏览:214
怎么编程枪战 发布:2024-11-24 21:25:52 浏览:855
安卓公测版哪个好 发布:2024-11-24 21:15:58 浏览:873
androidforvs2010 发布:2024-11-24 21:06:05 浏览:286
安装MySqllinux 发布:2024-11-24 21:05:51 浏览:326
联通网洛盒的密码在哪里 发布:2024-11-24 21:05:12 浏览:181
牌顺编程 发布:2024-11-24 20:56:23 浏览:729