原著網址:http://m.blog.csdn.net/blog/u013716863/37662943 http://m.blog.csdn.net/blog/u013716863/37663325
一. 什麼是自定義XML屬性
在我們使用自定義的控件時,很多時候都需要定義一些不同於一般的XML屬性前綴(如android:layout_width)的屬性,比如這樣 app:textColor,這些就是自定義控件需要用到的自定義控件屬性。
二. 自定義XML屬性有什麼用
自定義XML屬性的作用在於,在採取自定義的控件時,很多時候,系統的一般XML屬性已經不能滿足需求,比如我們在做一個具有描邊效果的TextView時,就需要有額外定義的TextView外邊框顏色和TextView內部顏色兩種顏色。這時候,使用自定義XML屬性,用戶就可以很方便地在XML中配置額外的屬性。
三. 怎麼使用自定義XML屬性
1.定義對應的屬性
在values文件夾下新建一個attar_custom.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 自定義控件的名稱 -->
<declare-styleable name="StrokeTextView">
<!-- 自定義的屬性名稱 和對應的單位 -->
<attr name="outerColor" format="color|reference" />
<attr name="innnerColor" format="color|reference" />
</declare-styleable>
</resources>
2.在XML中定義自定義屬性
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.example.demo.StrokeTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"
android:textSize="28sp"
app:outerColor="#000000"
app:innnerColor="#ffffff"
android:layout_centerInParent="true"/>
</RelativeLayout>
注意,自定義的XML屬性必須給自定義的控件使用
3.使用自定義的XML屬性
public StrokeTextView(Context context, AttributeSet attrs) {
super(context, attrs);
m_TextPaint = this.getPaint();
//獲取自定義的XML屬性名稱
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.StrokeTextView);
//獲取對應的屬性值
this.mInnerColor = a.getColor(R.styleable.StrokeTextView_innnerColor,0xffffff);
this.mOuterColor = a.getColor(R.styleable.StrokeTextView_outerColor,0xffffff);
案例:
效果圖
源碼
1.定義XML屬性:
<resources>
<!-- 自定義控件的名稱 -->
<declare-styleable name="StrokeTextView">
<!-- 自定義的屬性名稱 和對應的單位 -->
<attr name="outerColor" format="color|reference" />
<attr name="innnerColor" format="color|reference" />
</declare-styleable>
</resources>
2.使用XML定義描邊TextView的屬性
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.example.demo.StrokeTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"
android:textSize="28sp"
app:outerColor="#000000"
app:innnerColor="#ffffff"
android:layout_centerInParent="true"/>
</RelativeLayout>
3.重繪TextView
public class StrokeTextView extends TextView {
TextPaint m_TextPaint;
int mInnerColor;
int mOuterColor;
public StrokeTextView(Context context,int outerColor,int innnerColor) {
super(context);
m_TextPaint = this.getPaint();
this.mInnerColor = innnerColor;
this.mOuterColor = outerColor;
// TODO Auto-generated constructor stub
}
public StrokeTextView(Context context, AttributeSet attrs) {
super(context, attrs);
m_TextPaint = this.getPaint();
//獲取自定義的XML屬性名稱
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.StrokeTextView);
//獲取對應的屬性值
this.mInnerColor = a.getColor(R.styleable.StrokeTextView_innnerColor,0xffffff);
this.mOuterColor = a.getColor(R.styleable.StrokeTextView_outerColor,0xffffff);
}
public StrokeTextView(Context context, AttributeSet attrs, int defStyle,int outerColor,int innnerColor) {
super(context, attrs, defStyle);
m_TextPaint = this.getPaint();
this.mInnerColor = innnerColor;
this.mOuterColor = outerColor;
// TODO Auto-generated constructor stub
}
private boolean m_bDrawSideLine = true; // 默認採用描邊
/**
*
*/
@Override
protected void onDraw(Canvas canvas) {
if (m_bDrawSideLine) {
// 描外層
// super.setTextColor(Color.BLUE); // 不能直接這麼設,如此會導致遞歸
setTextColorUseReflection(mOuterColor);
m_TextPaint.setStrokeWidth(5); // 描邊寬度
m_TextPaint.setStyle(Style.FILL_AND_STROKE); // 描邊種類
m_TextPaint.setFakeBoldText(true); // 外層text採用粗體
m_TextPaint.setShadowLayer(1, 0, 0, 0); // 字體的陰影效果,可以忽略
super.onDraw(canvas);
// 描內層,恢復原先的畫筆
// super.setTextColor(Color.BLUE); // 不能直接這麼設,如此會導致遞歸
setTextColorUseReflection(mInnerColor);
m_TextPaint.setStrokeWidth(0);
m_TextPaint.setStyle(Style.FILL_AND_STROKE);
m_TextPaint.setFakeBoldText(false);
m_TextPaint.setShadowLayer(0, 0, 0, 0);
}
super.onDraw(canvas);
}
/**
* 使用反射的方法進行字體顏色的設置
* @param color
*/
private void setTextColorUseReflection(int color) {
Field textColorField;
try {
textColorField = TextView.class.getDeclaredField("mCurTextColor");
textColorField.setAccessible(true);
textColorField.set(this, color);
textColorField.setAccessible(false);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
m_TextPaint.setColor(color);
}
}