Android组件体系之视图绘制

一、View组件
View组件有几个重要的方法需要关注,也是自定义View经常需要重写的方法。

1、measure
作用是测量View组件的尺寸。对应的方法是onMeasure,测量View的宽和高。View和 ViewGroup都有measure方法,但ViewGroup除了测量自身尺寸,还要遍历地调用子元素的measure方法。

2、layout
用于确定布局位置。对应的方法是layout、onLayout,用于确定元素的位置,ViewGroup中的layout方法用来确定子元素的位置。

3、draw
作用是绘制内容背景,包括View的内容、子View的内容和背景。具体方法包括:drawBackground、onDraw、ViewGroup.dispatchDraw。

这个方法有个关键的入参也是唯一的入参:Canvas。其在native层有个对应的画布组件SkCanvas,该组件内部封装的SkBitmap实现了类似画纸的功能。

在Android系统中,View.draw的部分实现如下:

        // Step 1, draw the background, if needed
        int saveCount;       
        if (!dirtyOpaque) {
            drawBackground(canvas);
        }

        // skip step 2 & 5 if possible (common case)
        final int viewFlags = mViewFlags;
        boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
        boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
        
if (!verticalEdges && !horizontalEdges) {
            // Step 3, draw the content          
            if (!dirtyOpaque) {
                long logTime = System.currentTimeMillis();
                onDraw(canvas);                
            }
            ...

            // Step 4, draw the children
            dispatchDraw(canvas);
            drawAutofilledHighlight(canvas);

            // Overlay is part of the content and draws beneath Foreground
            if (mOverlay != null && !mOverlay.isEmpty()) {
                mOverlay.getOverlayView().dispatchDraw(canvas);
            }

            // Step 6, draw decorations (foreground, scrollbars)
            onDrawForeground(canvas);

其中绘制背景的实现,是通过Drawable类型的变量mBackground也就是背景图来完成的。View中的onDraw是个空方法,但在具体的View组件例如ImageView中,都会有对应的扩展实现。

这里的绘制,主体功能通常是Drawable和Canvas,后者处理绘制区域、矩阵变换等工作,前者根据组件功能,实现具体绘制操作,例如BitmapDrawable中的draw方法,最终是通过Paint画笔组件和Canvas的drawBitmap方法实现绘制操作的。

对于自定义视图组件,通常需要重写onDraw方法,并在该方法中调用Canvas的drawXXX例如drawBitmap、drawText等方法来实现预期的效果,如果涉及到几何变换,还可能会用到Matrix组件。

二、Canvas组件
作为绘制处理中的画布组件,Canvas提供了裁剪区域/路径和多种图形/图像绘制功能,对应的方法有:

  • clipRect、clipPath、clipRegion;
  • drawBitmap、drawTex、drawLine;

具体实现都是在native层完成的,涉及SkiaCanvas、SkCanvas。

    public boolean clipRect(@NonNull RectF rect, @NonNull Region.Op op) {
        checkValidClipOp(op);
        return nClipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
    }

在framework层的android_graphics_Canvas.cpp中,有对应实现:


static jboolean clipRect(jlong canvasHandle, jfloat l, jfloat t,
                         jfloat r, jfloat b, jint opHandle) {
    bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b,
            opHandleToClipOp(opHandle));
    return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
}

该方法会调用到SkiaCanvas.cpp中的实现,这里先不展开分析。

三、融合与思考

1、Activity、Window和View之间关系
1)Window和PhoneWindow
PhoneWindow类,派生于Window,是连接Activity跟View的桥梁,所有Activity对View的操作都需要借助它。

2)Activity和Window
在Activity启动过程中,系统会调用attach方法,并创建PhoneWindow实例;之后,在具体Activity的onCreate函数中,通常都会调用setContentView方法,进而调用PhoneWindow的setContentView方法设置DecorView。

3)Window和View
Window通过WindowManagerImp类型的成员变量mWindowManager操作View。WindowManagerImpl是WindowManager接口的具体实现,该类通过WindowManagerGlobal完成addView、removeView、updateViewLayout这三个方法。
进一步地,PhoneWindow的成员变量DecorView,可以通过getViewRootImpl方法获取ViewRoot实例。与之对应的ViewRootImpl类,有个IWindowSession类型的成员变量mWindowSession,能够访问WMS。

小结:PhoneWindow类,是连接Activity跟View的桥梁;而ViewRootImpl是 View 和 WindowMangerService之间的桥梁。

(相关完整且成体系的文章,可参见本人原创的开源电子书《Android系统与性能优化》,地址:https://github.com/carylake/androidnotes)

原文地址:https://www.cnblogs.com/carylake/p/12040463.html

时间: 2024-10-09 09:32:02

Android组件体系之视图绘制的相关文章

Android组件体系之Activity启动模式解析

本文主要分析Activity的启动模式及使用场景. 一.Activity启动模式浅析 1.standard 标准模式,系统默认的启动模式.在启动Activity时,系统总是创建一个新的Activity实例.其缺点是:复用性差.占用内存,当Activity已经在栈顶时,还是会创建实例. 2.singleTop 这种模式可以实现栈顶复用的效果. 如果目标Activity已经存在于栈顶,则调用实例的 onNewIntent,否则创建一个新的实例,可以用于通知启动的内容显示,例如新闻客户端的内容页面.信

Android View体系(一)视图坐标系

前言 Android View体系是界面编程的核心,他的重要性不亚于Android四大组件,在这个系列中我会陆续讲到View坐标系.View的滑动.View的事件分发等文章来逐步介绍Android View体系. 1.View简介 View是Android所有控件的基类,同时ViewGroup也是继承自View,看下面这张图我们就会有一个直观的了解: 我们知道了View的层级关系有助于我们对View的理解,我们看到我们常用的这些控件都是继承于View,如果我们更好的掌握了View的知识体系,那么

Android视图绘制流程完全解析,带你一步步深入了解View(二)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/16330267 在上一篇文章中,我带着大家一起剖析了一下LayoutInflater的工作原理,可以算是对View进行深入了解的第一步吧.那么本篇文章中,我们将继续对View进行深入探究,看一看它的绘制流程到底是什么样的.如果你还没有看过我的上一篇文章,可以先去阅读 Android LayoutInflater原理分析,带你一步步深入了解View(一) . 相 信每个Android

关于Android界面编程与视图(View)组件

UI组件--------------->android.widget.* View组件------------->android.view.* 视图(View)组件 所有UI组件都是建立在视图(View)组件.容器(ViewGroup)组件基础之上的. UI组件继承之View组件 ViewGroup----------->作为其他组件的容器使用. ViewGroup包含View组件即 (UI组件---->继承自View组件. ViewGroup组件---->继承自View组件

Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解

今天继续给大家分享下View的相关知识,重点有一下两点:   1.View的几种不同状态属性            2.如何根据不同状态去切换我们的背景图片. 开篇介绍:android背景选择器selector用法汇总 对Android开发有经验的同学,对 <selector>节点的使用一定很熟悉,该节点的作用就是定义一组状态资源图片,使其能够 在不同的状态下更换某个View的背景图片.例如,如下的hello_selection.xml文件定义: <?xml version="

(转)Android视图绘制流程完全解析,带你一步步深入了解View(二)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/16330267 在上一篇文章中,我带着大家一起剖析了一下LayoutInflater的工作原理,可以算是对View进行深入了解的第一步吧.那么本篇文章中,我们将继续对View进行深入探究,看一看它的绘制流程到底是什么样的.如果你还没有看过我的上一篇文章,可以先去阅读 Android LayoutInflater原理分析,带你一步步深入了解View(一) . 相信每个Android程

Android View体系(二)实现View滑动的六种方法

相关文章: Android View体系(一)视图坐标系 1.View的滑动简介 View的滑动是Android实现自定义控件的基础,同时在开发中我们也难免会遇到View的滑动的处理.其实不管是那种滑动的方式基本思想都是类似的:当触摸事件传到View时,系统记下触摸点的坐标,手指移动时系统记下移动后的触摸的坐标并算出偏移量,并通过偏移量来修改View的坐标. 实现View滑动有很多种方法,这篇文章主要讲解六种滑动的方法,分别是:layout().offsetLeftAndRight()与offs

Android View体系(八)从源码解析View的layout和draw流程

相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源码解析Scroller Android View体系(五)从源码解析View的事件分发机制 Android View体系(六)从源码解析Activity的构成 Android View体系(七)从源码解析View的measure流程 前言 上一篇文章我们讲了View的measure的流程,接下来我们

自定义Android组件之组合方式创建密码框组件

Android中所有控件(也称组件)都继承自adnroid.view.View类,android.view.ViewGroup是View类的重要子类,绝大多书的布局类就继承自ViewGroup类. 附上一张基于Android Api21的View和Widget类图 自定义Android组件基本可以从2个入口着手,一是继承Viewe类拿起画笔和画布绘制组件,而是通过继承View的子类和组合已有的组件的方式构造自定义的组件. 本文通过自定义一个PassWordView组件来实现密码能够通过点击点选框