天天看點

Android自定義控件(十二)——自定義屬性及應用

本文目錄

  • 如何自定義屬性
    • format取值類型
    • 引入自定義屬性
    • 代碼中擷取自定義屬性
    • 自定義屬性畫圓

如何自定義屬性

我們經常使用XML引入各種控件,比如TextView,Button等,使用過程中,我們通過設定各種屬性值,讓控件變的多姿多彩,比如我們使用android:layout_width定義控件的寬度,使用android:layout_height定義控件的高度。那麼現在我有一個需求,我想自己定義個圓的屬性,畫一個閉合的圓形應該怎麼做?我們先來看一段代碼:

<com.liyuanjinglyj.customproperty.CircleView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:radius="250"
    app:CircleX="250"
    app:CircleY="250"/>
           

這裡引入了一個部落客自己定義的View,看看最後三個屬性,是不是沒見過?這就是自定義的屬性值,我們在這裡設定了自定義屬性的半徑,以及圓心位置。那麼這些屬性在哪裡?

在小編建立的attrs.xml檔案中,代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CircleView">
        <attr name="radius" format="integer"/>
        <attr name="CircleX" format="integer"/>
        <attr name="CircleY" format="integer"/>
    </declare-styleable>
</resources>
           

所有自定義的屬性都是通過declare-styleable标簽實作的,而它的name,就是自定義控件的類名,這一點不能變,也不能改,這是死規則。也就是說哪個類用的自定義屬性值,name就是哪個類名。

在來看看其中定義的三個屬性,他們的名字分别是radius,CircleX,CircleY,也就是上面控件直接引入的值,後面的format,就是引入的值的類型。比如這樣屬性必須傳入int類型。

我們上面自定義的屬性format是一個integer值,這個也算是非常常用的,但我們除了這些常會用的,比如,boolean,string,float等,還有三個類型值,分别是:

(1)reference:指的是從string.xml,drawable.xml,以及color.xml等檔案中引入過來的值,比如常常在ImagView中使用的android:src="@drawable/background",這種引入值就使用這個類型。

(2)flag:是自己定義的值,比如android:gravity=“top”,以及如下自定義屬性代碼:

<attr name="age">
	<flag name="child" value="10"/>
	<flag name="young" value="18"/>
	<flag name="old" value="60"/>
</attr>

<!--XML中使用屬性app:age="child"-->
           

這種方式,常用在在幾個選項中,選擇設定的需求中,比如排版問題上的,隻能選居中,左對齊,右對齊等,其他的不需要。

(3)dimension:指的是從dimension.xml檔案中引入過來的值,特别需要注意的是,如果這個是dp,就會進行像素轉換。

雖然說自定了上面的屬性類型,但并不能直接在代碼中引用,還要先導入自定義屬性集才能使用,這裡我們有兩種導入方式:

xmlns:app="http://schemas.android.com/apk/res/com.liyuanjinglyj.customproperty"
xmlns:app="http://schemas.android.com/apk/res-auto"
           

推薦使用第二章方式導入,當然,他們都是引入到XML根控件之中的,但這裡還需要解釋兩點。

(1)app這個是自定義的,這個可以定義成任何你想要的内容,你定義liyuanjing,那麼就通過liyuanjing:radius引入自定義屬性,其他字元類同。

(2)如果使用第一種引入方式,那麼apk/res/後面的就是你程式的包名,包名在AndroidManifest.xml根節點的package屬性中。

既然我們在XML中引入了自定義屬性以及自定義的View,肯定是要用到這些屬性的,是以我們還要掌握在程式中如何使用這些屬性,代碼如下:

public CircleView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.CircleView);//擷取自定義屬性
    this.radius=typedArray.getInt(R.styleable.CircleView_radius,50);
    this.circleX=typedArray.getInt(R.styleable.CircleView_CircleX,25);
    this.circleY=typedArray.getInt(R.styleable.CircleView_CircleY,25);
    typedArray.recycle();
}
           

首先,我們在自定義View的構造函數中,有一個attrs參數,這個參數就是擷取設定屬性用的,我們可以通過context.obtainStyledAttributes擷取到自定義屬性,然後根據類型擷取到設定的值,比如這裡擷取的integer類型,第二個參數是預設值。當沒有在XML中設定這個屬性的時候,使用預設值。

備注:還有這裡需要注意以下,使用完成之後,記得釋放TypedArray資源。

上面我們已經都介紹完,如何自定義屬性,以及擷取屬性值的方式,這裡我們來自定義一個CircleView來根據XML設定的值,畫一個圓,自定義View代碼如下:

public class CircleView extends View {
    private int radius;
    private int circleX,circleY;
    private Paint paint;
    public CircleView(Context context) {
        super(context);
    }

    public CircleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.CircleView);//擷取自定義屬性
        this.radius=typedArray.getInt(R.styleable.CircleView_radius,50);
        this.circleX=typedArray.getInt(R.styleable.CircleView_CircleX,25);
        this.circleY=typedArray.getInt(R.styleable.CircleView_CircleY,25);
        typedArray.recycle();
        this.paint=new Paint();
        this.paint.setColor(Color.RED);
        this.paint.setStyle(Paint.Style.FILL);
        this.paint.setStrokeWidth(6);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(this.circleX,this.circleY,this.radius,this.paint);
    }

    public CircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}
           
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <com.liyuanjinglyj.customproperty.CircleView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:radius="250"
        app:CircleX="250"
        app:CircleY="250"/>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher_background"/>

</LinearLayout>
           

繼續閱讀