Android 自定义控件基础知识

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HUandroid/article/details/90054624

Android 自定义控件基础知识

我一般写自定义控件步骤是这样的:

  • 规划onDraw onLayout里面需要用到那些知识点
  • 根据设定的自定义效果,提前规划出自定义属性(也可以最后提取)
  • onMeasuae的测量模式
  • 实现onDraw绘图效果
  • onLayout的实现(是否需要)
  • 检测 是否需要开启硬件加速,是否存在内存泄漏 ,对外暴露方法

自定义属性

在res/values下创建attrs.xml文件,写自定义属性:比如

<declare-styleable name="ArcGradualView">
        <attr name="color_gradual_start" format="color" />
        <attr name="color_gradual_end" format="color" />
        <attr name="height_arc" format="dimension" />
        <attr name="gradual_or">
            <!--水平方向-->
            <enum name="orizontal" value="0" />
            <!--垂直方向-->
            <enum name="vertical" value="1" />
            <!--对角线45-->
            <enum name="angles45" value="2" />
            <!--对角线135-->
            <enum name="angles135" value="3" />
        </attr>
        <attr name="color_other_arc" format="color" />
    </declare-styleable>

其中name代表你自定义控件的名字
导入自定义属性需要注意的是,要让XML识别出来,需要在跟布局里加入:

 <com.hujin.test.view.ArcGradualView
           android:id="@+id/header_view"
           app:height_arc="30dp"
           app:color_gradual_start="@color/colorAccent"
           app:color_gradual_end="@color/colorPrimary"
           app:gradual_or="vertical"
           app:color_other_arc="@android:color/black"
           android:layout_width="match_parent"
           android:layout_height="200dp"/>
xmlns:app="http://schemas.android.com/apk/res-auto"

其中app是你的自定义属性标识,可以随意命名。

declare-styleable标签
  1. reference 某个资源的ID
    属性定义:
  <declare-styleable name="ArcGradualView">
      <attr name="src" format="reference"/>
    </declare-styleable>

属性使用:

 <com.example.hasee.widget.ArcGradualView
        app:src="@drawable/bg_white_point"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  1. color 颜色值
    属性定义
  <declare-styleable name="ArcGradualView">
      <attr name="bgColor" format="color"/>
    </declare-styleable>

属性使用:

  <com.example.hasee.widget.ArcGradualView
        app:bgColor="#FFFFFF"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  1. boolean 布尔值
    属性定义:
<declare-styleable name="ArcGradualView">
      <attr name="isFocusable" format="boolean"/>
    </declare-styleable>

属性使用:

    <com.example.hasee.widget.ArcGradualView
        app:isFocusable="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  1. dimension 尺寸值

属性定义

  <declare-styleable name="ArcGradualView">
      <attr name="line_width" format="dimension"/>
    </declare-styleable>

属性使用

<com.example.hasee.widget.ArcGradualView
        app:line_width="@dimen/dp_10"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  1. float浮点值
    属性定义
<declare-styleable name="ArcGradualView">
      <attr name="startAlpha" format="float"/>
      <attr name="endAlpha" format="float"/>
    </declare-styleable>

属性使用

<com.example.hasee.widget.ArcGradualView
        app:startAlpha="0.0"
        app:endAlpha="1.0"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  1. integer整型值
    属性定义

    <declare-styleable name="ArcGradualView">
      <attr name="job_level" format="integer"/>
    </declare-styleable>

属性使用

  <com.example.hasee.widget.ArcGradualView
        app:job_leveal="3"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  1. string 字符串

属性定义

  <declare-styleable name="ArcGradualView">
        <attr name="apiId" format="string"/>
    </declare-styleable>

属性使用

  <com.example.hasee.widget.ArcGradualView
        app:apiId="123456789"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  1. fraction 百分数
    属性定义
    <declare-styleable name="ArcGradualView">
        <attr name="pivotX" format="fraction"/>
        <attr name="pivotY" format="fraction"/>
    </declare-styleable>

属性使用

  <com.example.hasee.widget.ArcGradualView
        app:pivotX="200%"
        app:pivotY="300%"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  1. enum 枚举值
    属性定义
 <declare-styleable name="ArcGradualView">
        <attr name="gradual_or">
            <enum name="horizontal" value="0" />
            <enum name="vertical" value="1" />
            <enum name="angles45" value="2" />
            <enum name="angles135" value="3" />
        </attr>
    </declare-styleable>

属性使用:

<com.example.hasee.widget.ArcGradualView
        app:gradual_or="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

枚举属性 只能写入列举的值之一
在这里插入图片描述
10.flag 位或运算
属性定义

 <declare-styleable name="ArcGradualView">
        <attr name="flagMode">
            <flag name="right" value="0" />
            <flag name="left" value="1" />
            <flag name="top" value="2" />
            <flag name="bottom" value="3" />
        </attr>
    </declare-styleable>

属性使用

 <com.example.hasee.widget.ArcGradualView
        app:flagMode="right|top"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

对于flag位或运算,如果变量比较少,建议是计算完后,使用enum枚举值去处理。

往往xml中定义的属性,希望是初始化的属性值,是静态的。而需求经常需要动态的,就需要重写该属性的get)_set()方法暴露出去,动态更新view。
这里要理解invalidate()requestLayout()的更新区别:

invalidate() —onDraw()

请求重绘View树,即draw()过程,假如视图发生大小没有变化就不会调用layout()过程,并且只绘制那些“需要重绘的”视图,即谁(View的话,只绘制该View ;ViewGroup,则绘制整个ViewGroup)请求invalidate()方法,就绘制该视图。
一般方法会重新调用invalidate()

  • 直接调用invalidate()方法:请求重新draw(),但只会绘制调用者本身
  • setSelection()方法 :请求重新draw(),但只会绘制调用者本身
  • setVisibility()方法 : 当View可视状态在INVISIBLE转换VISIBLE时,会间接调用invalidate()方法,继而绘制该View。
  • setEnabled()方法 : 请求重新draw(),但不会重新绘制任何视图包括该调用者本身。
requestLayout()—onMeasure() 和onLayout() 或 onDraw()

只是对View树重新布局layout过程包括measure()和layout()过程。对于是否会调用draw()方法,大佬分析是:on在onLayout中发现r,l,t,b的值发生改变,就会重走draw()。
一般方法会重新调用requestLayout()

  • 直接调用requestLayout()方法:请求重新onMeasure()和 onLayout(),但不会重新绘制。View只会走onMeasure()。
  • setVisibility()方法:当View的可视状态在INVISIBLE/ VISIBLE 转换为GONE状态时,会间接调用requestLayout() 和invalidate方法。 同时,由于整个个View树大小发生了变化,会请求measure()过程以及draw()过程,同样地,只绘制需要“重新绘制”的视图。

测量onMeasure

以后再写

猜你喜欢

转载自blog.csdn.net/HUandroid/article/details/90054624
今日推荐