自定义View

自定义View可以分为两大类,一种是自定义View,一种是自定义ViewGroup;其中自定义View又分为继承View和继承系统控件两种。

1.继承系统控件的自定义View

这种自定义View在系统控件的基础上进行拓展,一般是添加新的功能或者修改显示的效果,一般情况下我们在onDraw()方法中进行处理

自定义view时只需要重写onMeasure()和onDraw()

自定义viewGroup时只需要重写onMeasure()和onLyaout()

public class MyTextView extends View {
    //当在代码中创建一个 View 的时候使用
    //这个构造函数就是在代码中直接 new view 的时候使用,这样出来的 View 默认是没有任何的属性值,需要后面自己手动 set。
    public MyTextView(@NonNull Context context) {
        super(context);
    }
    //当我们在 xml 中定义了 View 然后在代码中使用这个 View 的时候,这个 View 就是利用这个构造方法生成的。
    //View 的属性值来自 AttributeSet 的值
    //这个构造函数是在代码中生成对应 xml 中定义的 View 使用的。这个时候在 xml 中定义的属性值会通过 AttributeSet 传递,这样生成的 View 对象是有默认的属性值的
    public MyTextView(@NonNull Context context,
            @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    //这个构造方法就是提供了默认的 defStyleAttr 用于指定基本的属性
    //这个构造函数就是相对于第二个构造函数,多提供了一种给 View 添加默认属性的方式,通过 deftStyleAttr 如果没有默认的值,就用 0 。
    public MyTextView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    //第四个构造函数相对第三个构造函数就多了一个 defStyleRes ,说白了就是多了一种提供 View 默认属性的一种方式。这种方式更加的简单,直接在代码中传入 R.style.XX 就可以了。如果没有默认值的话就为 0 。这个参数只有 defStyleAttr 为 0 的时候才会生效。
    public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
}

自定义属性

  • AttributeSet与自定义属性
    系统自带的View可以在xml中配置属性,对于写的好的自定义View同样可以在xml中配置属性,为了使自定义的View的属性可以在xml中配置,需要以下4个步骤:
  • 1、通过<declare-styleable> 为自定义View添加属性
  • 2、在xml中为相应的属性声明属性值
  • 3、在运行时(一般为构造函数)获取属性值
  • 4、将获取到的属性值应用到View

android系统的控件以android开头的比如android:layout_width,这些都是系统自带的属性,为了方便配置MyTextView的属性,我们也可以自定义属性,首先在values目录下创建 attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyTextView">
        <attr name="textcolor" format="color"/>
    </declare-styleable>
</resources>

在构造方法中解析自定义view的属性

public MyTextView(@NonNull Context context,
            @Nullable AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyTextView);
        typedArray.getColor(R.styleable.MyTextView_textcolor,1);
        //获取资源后要及时回收
        typedArray.recycle();
    }

在xml里使用自定义属性

   <com.example.myview.view.MyTextView
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       app:textcolor="@color/black"/>

三个过程

三个动作对应的意义
测量:onMeasure()决定View的大小;
布局:onLayout()决定View在ViewGroup中的位置;
绘制:onDraw()决定绘制这个View。

MeasureSpec

1.MeasureSpec的Model可以分为以下三种模式:

  • UNSPECIFIED:父视图不对View大小做限制,这种情况一般用于系统内部, 表示一种测量状态。(这个模式主要用于系统内部多次Measure的情形,并不是真的说你想要多大最后就真有多大)。
  • EXACTLY:父控件已经知道你所需的精确大小,你的最终大小应该就是这么大,如:100dp
  • AT_MOST:子视图的大小不能大于父控件给你指定的size,但具体是多少,得看你自己的实现。如:matchParent, 最大不能超父视图。

2、getMeasureWidth与getWidth的区别

  • getMeasuredWidth
    在measure()过程结束后就可以获取到对应的值;
    通过setMeasuredDimension()方法来进行设置的。

  • getWidth
    在layout()过程结束后才能获取到;
    通过视图右边的坐标减去左边的坐标计算出来的。

 父视图与子视图的关系

 

  • 当view采用固定宽高的时候,不管父容器的MeasureSpec是什么,view的MeasureSpec都是精确模式并且其大小遵循Layoutparams中的大小;
  • 当view的宽高是match_parent时,这个时候如果父容器的模式是精准模式,那么view也是精准模式并且其大小是父容器的剩余空间,如果父容器是最大模式,那么view也是最大模式并且其大小不会超过父容器的剩余空间;
  • 当view的宽高是wrap_content时,不管父容器的模式是精准还是最大化,view的模式总是最大化并且大小不能超过父容器的剩余空间。
  • Unspecified模式,这个模式主要用于系统内部多次measure的情况下,一般来说,我们不需要关注此模式(这里注意自定义View放到ScrollView的情况 需要 处理)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaowang_lj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值