本文目錄
- 如何自定義屬性
-
- 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>