一. 什么是自定义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">  
自定义的属性名称 和对应的单位 -->  
outerColor" format="color|reference" />  
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  
    }  
  
默认采用描边  
  
    /**  
     *   
     */  
    @Override  
    protected void onDraw(Canvas canvas) {  
        if (m_bDrawSideLine) {  
描外层  
不能直接这么设,如此会导致递归  
            setTextColorUseReflection(mOuterColor);  
描边宽度  
描边种类  
外层text采用粗体  
字体的阴影效果,可以忽略  
            super.onDraw(canvas);  
  
描内层,恢复原先的画笔  
  
不能直接这么设,如此会导致递归  
            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);  
    }  
  
}