温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Android-UI控件的绘制流程以及自定义控件的具体操作

发布时间:2020-06-21 11:06:57 来源:网络 阅读:1648 作者:DavidWillo 栏目:移动开发

  View视图安卓应用中非常重要的组成部分,它不仅是构成应用界面的基本单元,还是与用户交互的最直接对象。视图View作为界面的基本元素,是由View System进行管理的。

  在Android中,视图控件主要被分成两大类,一类是单一控件View,另外一类是可以包含并管理子控件的ViewGroup,在一个界面布局中,ViewGroup与View的嵌套与组合,就构成了一棵控件树,经过一系列流程绘制在屏幕上,形成完整的用户界面。

Android-UI控件的绘制流程以及自定义控件的具体操作

   View是最基本的UI类,几乎所有的控件都继承于View,广义的View指的是除了ViewGroup外的如TextView,CheckBox、Button、EditText、RadioButton等的单一控件,它们管理自身的绘制以及对事件的处理。而ViewGroup是View 的子类,同时作为View控件的容器而存在,ViewGroup可以控制各个子View 的显示层次与位置,同时可以对焦点获取、触摸等交互事件进行处理、拦截或分发。

  视图的绘制主要分为三个步骤,分别为Measure,Layout跟Draw。

  在Measure操作中,测量的操作的分发由ViewGroup来完成,ViewGroup通过对子节点进行遍历并分发测量操作,在具体的测量过程中,根据父节点的MeasureSpec以及子节点的LayoutParams等信息计算子节点的宽高,最终整理成父容器的宽高,具体的测量方式,我们也可以通过重写onMeasure方法来设定。

  紧接着,通过Layout过程,来确定每一个View在父容器中的具体位置,同样的,我们也可以通过onLayout方法来自定义具体的布局流程。

  最后进入Draw的绘制流程,根据前两步所获得的具体布局参数,在draw函数中对各控件进行绘制,绘制的顺序为背景-控件内容-子控件绘制-绘制边缘以及滚动条等装饰物。

  总体来说,控件的绘制都是在控件树上进行的,由ViewGroup分发给子View各自完成自身的测量与布局操作,最后由根节点开始进行绘制,最终形成完整的界面。

  最后选择一个具体的例子来观察View的绘制流程吧。

  首先我们看一下TextView的具体绘制流程:

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);

    int heightMode = MeasureSpec.getMode(heightMeasureSpec);

    int widthSize = MeasureSpec.getSize(widthMeasureSpec);

    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int width;

    int height;

    

    ......

    

    setMeasuredDimension(width, height);

}

  传入的MeasureSpec是一个32位的整数,高两位表示测量模式,低30位表示规格大小,这个整数指定了控件将如何进行具体的测量。最后利用更新后的width跟height设置测量结果的宽高。这个函数的主要作用是计算是否有margin/padding等造成额外的宽高,在必要时预留空间,并确定view的大小。

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

    super.onLayout(changed, left, top, right, bottom);

    if (mDeferScroll >= 0) {

        int curs = mDeferScroll;

        mDeferScroll = -1;

        bringPointIntoView(Math.min(curs, mText.length()));

    }

}



  在这里调用了父类的onLayout函数

/**

 * Called from layout when this view should

 * assign a size and position to each of its children.

 *

 * Derived classes with children should override

 * this method and call layout on each of

 * their children.

 * @param changed This is a new size or position for this view

 * @param left Left position, relative to parent

 * @param top Top position, relative to parent

 * @param right Right position, relative to parent

 * @param bottom Bottom position, relative to parent

 */

protected void onLayout

(boolean changed, int left, int top, int right, int bottom) {

}



 可以看到View中该函数的注释,可以知道这个函数的主要作用是对view的位置与大小进行赋值,以便下一步进行绘制。

@Override

protected void onDraw(Canvas canvas) {

    restartMarqueeIfNeeded();


    // Draw the background for this view

    super.onDraw(canvas);


    ......


    mTextPaint.setColor(color);

    mTextPaint.drawableState = getDrawableState();


    ......


    layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);

    ......


}



 onDraw函数在该view需要进行渲染时调用,设置了具体的画笔等参数,并调用draw进行具体绘制。


/**

 * Draw this Layout on the specified canvas, with the highlight path drawn

 * between the background and the text.

 *

 * @param canvas the canvas

 * @param highlight the path of the highlight or cursor; can be null

 * @param highlightPaint the paint for the highlight

 * @param cursorOffsetVertical the amount to temporarily translate the

 *        canvas while rendering the highlight

 */

public void draw(Canvas canvas, Path highlight, Paint highlightPaint,

        int cursorOffsetVertical) {

    final long lineRange = getLineRangeForDraw(canvas);

    int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);

    int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);

    if (lastLine < 0) return;


    drawBackground(canvas, highlight, highlightPaint, cursorOffsetVertical,

            firstLine, lastLine);

    drawText(canvas, firstLine, lastLine);

}



  在draw方法中分别调用对背景以及具体文字的绘制函数。 

  总而言之,我们可以重写这些方法,来完成我们的控件自定义操作。 


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI