自定義 View Attribute

上篇 提到自定義view RingProgressBar 

其中有些參數,如 ring color. text color, size等,這些不會改變的設定檔,能否在layout中直接定義好,不用在class終在做設定呢

讓自定義view有更方便的 reuse

這篇講解如何自訂義 view 中的屬性

 

前言

在設定前先說說,自定義有什麼好處?

首先Android Studio 有提供Priview layout 排版的功能。我們可以輕易看出layout中物件的樣式排版是否正確

而在code design中,有高內聚低耦合(high cohesion、low coupling) 。希望把相關東西放在一起(有點扯遠了)

所以在class中設定相關view的事情,除非不得已, 如: 動態的值或顏色,我是傾向放在view中設定,也比較好管理。

如下圖所示:

螢幕快照 2019-12-22 下午2.21.57.png

 

 

Attrs.xml

新增Attribute方式很簡單,當有自定義view之後,方可做這些定義。

1. 在 value 中新增attr的xml  (範例中打成 attr.xml 應該為attrs.xml)

螢幕快照 2019-12-22 下午1.35.41.png

 

2. 在<resources> </resources> 新增 view 屬性

螢幕快照 2019-12-22 下午1.35.17.png

 

新增屬性

以RingProgressBar為範例

使用 declare-stylealbe 綁定該屬性是誰的

<declare-styleable name="RingProgressBar">
    <attr name="bgRingColor" format="color" />
    <attr name="bgRingSize" format="dimension" />
    <attr name="pRingColor" format="color" />
    <attr name="pRingSize" format="dimension" />
    <attr name="textSize" />
    <attr name="textColor" />
    <attr name="RingPadding" format="dimension" />
    <attr name="progressValue" format="integer" />
</declare-styleable>

並在其中設定 相關屬性 <attr name="", format="格式"/>

可設定格式頗多種 以下會慢慢介紹

1. 基本類別:

  • string
  • integer
  • float
  • boolean
  • fraction: 百分比類型, 取直只能以%結尾 (很少用到)

2. resource: 

  • color
    • 使用方式 @color/, "#009900"
  • dimension
    • 設定數值用,  
  • reference
    • 可從其他resource files重取得值, 如 @string/XXX, @drawable/, @dimen/

3. 特殊類型

  • enum 枚舉
    • 在定義時,須在該attr節點下面加入enum節點,取值時只能取其中一個。(format 可加可不加)
      <attr name="progressSize" format="enum">
          <enum name="large" value="2" />
          <enum name="small" value="1" />
      </attr>
  • flags
    • 以 bit 為標記方式,與enum用法一樣,
    • 與enum差別在於 可以透過 “|” 來做計算
      <attr name="progressFlags" format="flags">
          <flag name="flag_0" value="0"/>
          <flag name="flag_1" value="1"/>
          <flag name="flag_2" value="2"/>
      </attr>

 

共用屬性

當自定義物件越來越多時,時常會發現某些屬性是相同,想要共用時該怎麼設定

簡單來說只需要做兩件事情

1. 把屬性拉出來,與"<declare-styleable></<declare-styleable>"同一層

2. 在使用該屬性時,不用設定format

 

Custom View 設定

範例以 koltin 語法寫,

class RingProgressBar @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    ...
    init {
        attrs?.let {
            val ta = context.obtainStyledAttributes(attrs, R.styleable.RingProgressBar)
            // TODO get value from ta
            // ta.getDimension(R.styleable.RingProgressBar_bgRingSize, 20f)

            ta.recycle()
        }
    }
}

TypedArray

在 RingProgressBar init 中,使用 “obtainStyledAttributes” 取得TypedArray。

TypedArray是個很重要的Object, 他可以幫我們做兩件事情

  1. 轉換attr id 與 屬性值的關係
  2. 取得layout 中設定的值,取得方式依據該attr format,如 attr format 是 string, 可用getString 取得 

 

詳細方式可去android developer 文件上找尋所有方法

 

參考

https://developer.android.com/training/custom-views/create-view

https://www.jianshu.com/p/813772e748c6

https://developer.android.com/reference/android/content/res/TypedArray