当前位置:   article > 正文

Android 自定义View

Android 自定义View

我们所有的试图都是起源于自定义View,包括ViewGroup也是继承于它,可以说它是视图组件之父。
我们可以从它的大致流程来分为四个部分:
构造方法,onMeasure,onLayout,onDraw

构造方法:

它主要有四个构造方法
分别为:

  • View(Context context)
  • public View(Context context, @Nullable AttributeSet attrs)
  • public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr)
  • public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)

关于attrs,defSyleAttr,defStyleRes介绍,源码中是这样说的
(一) attrs
attrs是一个int值,通过它一系列xml中一系列属性值的一个
它的作用:

  • 可以通过它来获取布局文件资源id值
    在这里插入图片描述
  • 在saveAttributeData中会默认先加载系统默认的属性值跟id,然后通过attrs加载已解析的可样式属性,比如说layout_marginTop,系统会给它一个默认的值,如果我们在xml当中进行修改,然后会将原值进行替换。
    在这里插入图片描述
    在这里插入图片描述
    (二)defStyleAttr
    Framework中源文件参数的介绍:

defStyleAttr An attribute in the current theme that contains a reference to a style resource that supplies default values for the view. Can be 0 to not look for defaults.

(三)defStyleRes介绍

defStyleRes A resource identifier of a style resource that supplies default values for the view, used only if defStyleAttr is 0 or can not be found in the theme. Can be 0 to not look for defaults

这两个参数在saveAttributeDataForStyleable中有参与但是看不到具体的内容在这里插入图片描述

onMeasure

它最终会调到
MeasureSpec:
MeasureSpec是一个32位的int值,高2位代表SpecMode,低30位代表SpecSize,SpecMode是指测量模式,SpecSize是指某种测量模式下的规格大小。

  • EXACTLY 父容器已经检测出View所需要的精确大小,这时候View的最终大小就是SpecSize所指定的值。对应于LauoutParams中的match_parent和具体数值这两种模式。
  • AT_MOST 父容器指定了一个可用大小即SpecSize,View的大小不能大于这个值,对应于LayoutParams中的wrap_content
  • UNSPECIFIED 父容器不对View有任何限制,要多大给多大,常用于系统内部,平常工作中不常见

普通View的MeasureSpec的创建规则:
在这里插入图片描述
onMeasure会调到setMeasureDimension方法
在这里插入图片描述
它会设置View 宽/高的测量值,因此只需要看getDefaultSize方法
在这里插入图片描述从这个方法来看,View的宽高由specSize决定,再结合MeasureSpec的创建规则表,得出结论:
直接继承View的自定义控件需要重写onMeasure方法并设置wrap_content时的自身大小,否则在布局中使用wrap_content就相当于使用match_parent。因为 View使用wrap,它的specMode是AT_MOST模式,宽高等于specSize,这情况下specSize为parentSize,而parentSize是父容器可使用的大小。

解决方法:

        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        
        if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(mWidth, mHeight);
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(mWidth, heightMeasureSpec);
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthMeasureSpec, mHeight);
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

onLayout

onLayout主要是视图位置的确定

onDraw

View的回值过程遵循如下几步:

  1. 绘制背景 background.draw
  2. 绘制自己 onDraw
  3. 绘制child dispatchDraw
  4. 绘制装饰 onDrawScrollBars

常见Canvas方法:
在这里插入图片描述
Paint常用方法:

paint.setStrokeWidth(0);//设置画笔宽度0  ,单位px  默认一个像素
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.STROKE);//描边 
paint.setStrokeWidth(10);//画笔宽度 10,单位px
paint.setAntiAlias(true);//抗锯齿功能
paint.setAlpha(); //设置画笔透明度
paint.setARGB();// 设置透明度 和 颜色
paint.setStyle()//设置画笔样式
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意:

  • 尽量不要在View中使用Handler
  • View中如果由线程或者动画,需要及时停止,可以在View#onDetachedFromWindow操作
  • 有嵌套滑动情形时,需要处理好滑动冲突
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/747755
推荐阅读
相关标签
  

闽ICP备14008679号