Android 自定义view基础

分类

自定义View按照组合方式大体分为如下两大类,四小类:

  1. 自定义单一View(不含子view)
    • 继承View
    • 继承View的子类(重写、增加功能,如:SurfaceView、TextView、Editext等)
  2. 自定义ViewGroup(包含子view)
    • 继承ViewGroup
    • 继承ViewGroup的子类(如:LinearLayout、RelativeLayout)

注:实际上ViewGroup也是继承View,但因为二者的组合方式不同,故分开处理。

流程

  • 自定义单一View
  1. 重写构造函数
  2. 自定义View的属性
  3. 获取自定义的属性
  4. 重新onMeasure(可省)
  5. 重写onDraw
  6. 使用自定义View
  • 自定义ViewGroup

重写构造函数

构造函数一共有4个,一般来说用前面3个即可:

  • View(Context context):Java代码中new后调用。
  • View(Context context, AttributeSet attrs):xml中定义后调用。
  • View(Context context, AttributeSet attrs, int defStyleAttr):可通过第一、二个构造函数间接调用,主要用来切换style的主题风格。
  • View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes):可通过第一、二个构造函数间接调用,而且需要在API 21之后才能使用,主要用来切换style的主题风格,同时需要defStyleRes的资源。

注意:为了方便获取自定义的属性,建议修改第一、二两个构造函数的super为this,让它们皆可调用第三个构造函数。第四个构造函数一般用不到,可以不生成。

    //1.Java代码中创建的,则调用第一个构造函数
    public CustomView(Context context) {
        //默认:super(context);
        //调用第二个构造函数
        this(context, null);
    }


    //2.当在xml中使用时,则调用第二个构造函数
    public CustomView(Context context, AttributeSet attrs) {
        //默认:super(context, attrs);
        //调用第三个构造函数
        this(context, attrs, 0);
    }

    //3.不会主动调用,一般是由第一第二个构造函数主动调用
    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView, defStyleAttr, 0);

        a.recycle(); // 解析后释放资源
        init();
    }

    //4.不会主动调用,并且仅在API 21后才能使用,因此除非你的minSdkVersion为21,否则不要使用它。
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public CustomView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

    }

自定义View的属性

declare-styleable
format 属性

format的作用就是对View的属性取值进行格式化,目前支持11种类型,已经涵盖了我们平时所需属性。

  1. color 颜色
  2. boolean 布尔
  3. dimension 尺寸
  4. enum 枚举
  5. flags 位或运算
  6. float 浮点型
  7. fraction 百分数
  8. integer 整型
  9. reference 参考资源ID
  10. String 字符串
  11. 混合类型
属性定义

values中新建一个cv_view_styles.xml文件,定义一下属性

<resources>
    <declare-styleable name="CustomView">
        <!--颜色-->
        <attr name="cv_color" format="color" />
        <!--布尔-->
        <attr name="cv_boolean" format="boolean" />
        <!--尺寸-->
        <attr name="cv_dimension" format="dimension" />
        <!--枚举-->
        <attr name="cv_enum">
            <enum name="cv_enum0" value="0" />
            <enum name="cv_enum1" value="1" />
        </attr>
        <!--位或运算-->
        <attr name="cv_flag">
            <flag name="flag0" value="0x1" />
            <flag name="flag1" value="0x2" />
            <flag name="flag2" value="0x3" />
            <flag name="flag3" value="0x4" />
        </attr>
        <!--浮点-->
        <attr name="cv_float" format="float" />
        <!--百分数-->
        <attr name="cv_" format="fraction" />
        <!--整型-->
        <attr name="cv_integer" format="integer" />
        <!--参考资源ID-->
        <attr name="cv_reference" format="reference" />
        <!--字符串-->
        <attr name="cv_string" format="string" />
        <!--混合-->
        <attr name="cv_hybrid" format="reference|color"/>
    </declare-styleable>
</resources>

属性获取

自定义CustomView.java中,获取以下属性

//      TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView,defStyleAttr,0);
        //获取颜色
        int mColor = a.getColor(R.styleable.CustomView_cv_color, Color.BLACK);
        //获取颜色(#D81B60或者selector类型的drawable资源)
        ColorStateList colorStateList = a.getColorStateList(R.styleable.CustomView_cv_color);
        //获取布尔
        boolean mBoolean = a.getBoolean(R.styleable.CustomView_cv_boolean, false);
        //获取尺寸
        float mDimension = a.getDimension(R.styleable.CustomView_cv_dimension, 3f);
        int mDimensionPixelSize = a.getDimensionPixelSize(R.styleable.CustomView_cv_dimension, 0);
        //获取浮点型
        float mFloat = a.getFloat(R.styleable.CustomView_cv_float, (float) 0.22);
        //获取枚举
        int mInt = a.getInt(R.styleable.CustomView_cv_enum, 0);
        //获取整型
        int mInteger = a.getInteger(R.styleable.CustomView_cv_integer, 0);
        //获取字符
        String mString = a.getString(R.styleable.CustomView_cv_string);
        //获取资源文件
        int resourceId = a.getResourceId(R.styleable.CustomView_cv_reference, 0);
        //获取drawable
        Drawable drawable = a.getDrawable(R.styleable.CustomView_cv_color);

属性使用

在使用自定View的属性之前,我们需要引入自定义的命名空间,有2种方式可行:
xmlns:app=“http://schemas.android.com/apk/res-auto” 或者xmlns:app="http://schemas.android.com/apk/com.brainbg.customview ,其中com.brainbg.customview为我们的应用程序包名,建议使用第一种方式,让系统自动查找。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
<!--或xmlns:app="http://schemas.android.com/apk/com.brainbg.customview"-->
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <com.brainbg.customview.CustomView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="30dp"
        app:cv_color="#3a819b"
        app:cv_boolean="true"
        app:cv_dimension="11dp"
        app:cv_enum="cv_enum0"
        app:cv_flag="flag0"
  <!--或app:cv_flag="flag0|flag1"-->
        app:cv_float="1.1"
        app:cv_fraction="90%"
        app:cv_integer="11"
        app:cv_reference="@mipmap/ic_launcher"
        app:cv_string="字符串"
        app:cv_hybrid="@mipmap/ic_launcher"
  <!--或app:cv_hybrid="#3a819b"-->
        />
</LinearLayout>

需要注意的是:枚举属性不能同时使用两个值,而位或运算则可以。所以定属性的时候,需要根据自己的需求,选择枚举、位或运算。

  • 有兴趣的话,可以去查看TextView源码的declare-styleable,路径:sdk/platforms/android-x/data/res/values/attrs.xml,以下是关于Textview的部分源码:
    <attr name="textColor" format="reference|color" />
    <attr name="typeface">
        <enum name="normal" value="0" />
        <enum name="sans" value="1" />
        <enum name="serif" value="2" />
        <enum name="monospace" value="3" />
    </attr>
    <attr name="textStyle">
        <flag name="normal" value="0" />
        <flag name="bold" value="1" />
        <flag name="italic" value="2" />
    </attr>
------------------------可以直接引用以上共用attr的值-------------------------
  <declare-styleable name="TextView">
        <attr name="bufferType">       
            <enum name="normal" value="0" />       
            <enum name="spannable" value="1" />
            <enum name="editable" value="2" />
        </attr>
        <attr name="textColor" />  
        <attr name="textScaleX" format="float" />
        <attr name="typeface" />
        <attr name="textStyle" />
        <attr name="numeric">
            <flag name="integer" value="0x01" />
            <flag name="signed" value="0x03" />
            <flag name="decimal" value="0x05" />
        </attr>
        <attr name="phoneNumber" format="boolean" />
        <attr name="inputMethod" format="string" />   
        <attr name="drawableTop" format="reference|color" />
        .....
        .....
    </declare-styleable>

注意:

  1. 属性定义时可以指定多种类型值:
<declare-styleable name="CustomView">
    <attr name="cv_background" format="reference|color" />
</declare-styleable>
// 使用
<ImageView
    android:layout_width="42dip"
    android:layout_height="42dip"
    android:background="@drawable/图片ID|#00FF00" />
  1. attr的name不可和系统及第三方的重复,否则会报错,如:Android resource compilation failed;尽量改用:自定义view的驼峰字母+属性的格式命名,如CustomView的背景色可以这么写:cv_background
<declare-styleable name="CustomView">
   <-- 切记不可写成 name="background" -->
    <attr name="cv_background" format="reference|color" />
</declare-styleable>
  1. 将公用的属性定义在declare-styleable标签之外,即可被多个自定义控件使用,可参考Textview的declare-styleable源码

注意事项

支持wrap_content、padding、margin

参考资料

https://www.jianshu.com/p/e9d8420b1b9c
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0806/4575.html

作者:Brainbg(白雨)
GitHub:https://github.com/Brainbg
博客:https://www.brainbg.com/
简书:https://www.jianshu.com/u/94518ede7100
CSDN:https://blog.csdn.net/u014720022

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值