天天看點

Android -- 自定義View

步驟

  1. 自定義View的屬性
  2. 在View的構造方法中獲得我們自定義的屬性
  3. 重寫onMesure
  4. 重寫onDraw

在res/values/下建立一個attrs.xml ,在裡面定義我們的屬性和聲明我們的整個樣式:

<?xml version="1.0" encoding="utf-8"?>  
<resources>  
  
    <attr name="titleText" format="string" />  
    <attr name="titleTextColor" format="color" />  
    <attr name="titleTextSize" format="dimension" />  
  
    <declare-styleable name="CustomTitleView">  
        <attr name="titleText" />  
        <attr name="titleTextColor" />  
        <attr name="titleTextSize" />  
    </declare-styleable>  
  
</resources>      

定義了字型,字型顔色,字型大小3個屬性。format是值該屬性的取值類型:一共有string,color,demension,integer,enum,reference,float,boolean,fraction,flag。

在布局中自定義View

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    xmlns:custom="http://schemas.android.com/apk/res-auto"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent" >  
  
    <com.yydcdut.CustomTitleView  
        android:layout_width="200dp"  
        android:layout_height="100dp"  
        custom:titleText="3712"  
        custom:titleTextColor="#ff0000"  
        custom:titleTextSize="40sp" />  
  
</RelativeLayout>      

xmlns:custom=http://schemas.android.com/apk/res-auto,命名空間,現在都是res-auto形式的了。

View的構造方法

/** 
     * 文本 
     */  
    private String mTitleText;  
    /** 
     * 文本的顔色 
     */  
    private int mTitleTextColor;  
    /** 
     * 文本的大小 
     */  
    private int mTitleTextSize;  
  
    /** 
     * 繪制時控制文本繪制的範圍 
     */  
    private Rect mBound;  
    private Paint mPaint;  
  
    public CustomTitleView(Context context, AttributeSet attrs)  
    {  
        this(context, attrs, 0);  
    }  
  
    public CustomTitleView(Context context)  
    {  
        this(context, null);  
    }  
  
    /** 
     * 獲得我自定義的樣式屬性 
     *  
     * @param context 
     * @param attrs 
     * @param defStyle 
     */  
    public CustomTitleView(Context context, AttributeSet attrs, int defStyle)  
    {  
        super(context, attrs, defStyle);  
        /** 
         * 獲得我們所定義的自定義樣式屬性 
         */  
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTitleView, defStyle, 0);  
        int n = a.getIndexCount();  
        for (int i = 0; i < n; i++)  
        {  
            int attr = a.getIndex(i);  
            switch (attr)  
            {  
            case R.styleable.CustomTitleView_titleText:  
                mTitleText = a.getString(attr);  
                break;  
            case R.styleable.CustomTitleView_titleTextColor:  
                // 預設顔色設定為黑色  
                mTitleTextColor = a.getColor(attr, Color.BLACK);  
                break;  
            case R.styleable.CustomTitleView_titleTextSize:  
                // 預設設定為16sp,TypeValue也可以把sp轉化為px  
                mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(  
                        TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));  
                break;  
  
            }  
  
        }  
        a.recycle();  
  
        /** 
         * 獲得繪制文本的寬和高 
         */  
        mPaint = new Paint();  
        mPaint.setTextSize(mTitleTextSize);  
        // mPaint.setColor(mTitleTextColor);  
        mBound = new Rect();  
        mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);  
  
    }      

我們重寫了3個構造方法,預設的布局檔案調用的是兩個參數的構造方法,是以記得讓所有的構造調用我們的三個參數的構造,我們在三個參數的構造中獲得自定義屬性。

重寫onDraw,onMesure

@Override  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
    {  
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
    }  
  
    @Override  
    protected void onDraw(Canvas canvas)  
    {  
        mPaint.setColor(Color.YELLOW);  
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);  
  
        mPaint.setColor(mTitleTextColor);  
        canvas.drawText(mTitleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);  
    }      
Android -- 自定義View

此時長寬都是固定的,當長寬都設定為wrap_content,會發現效果:

Android -- 自定義View

系統幫我們測量的高度和寬度都是MATCH_PARNET,當我們設定明确的寬度和高度時,系統幫我們測量的結果就是我們設定的結果,當我們設定為WRAP_CONTENT,或者MATCH_PARENT系統幫我們測量的結果就是MATCH_PARENT的長度。

是以,當設定了WRAP_CONTENT時,我們需要自己進行測量,即重寫onMesure方法”:

重寫之前先了解MeasureSpec的specMode,一共三種類型:

EXACTLY    //一般是設定了明确的值或者是MATCH_PARENT

AT_MOST    //表示子布局限制在一個最大值内,一般為WARP_CONTENT

UNSPECIFIED    //表示子布局想要多大就多大,很少使用      

重寫onMeasure

@Override  
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  {  
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);  
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);  
    int width;  
    int height ;  
    if (widthMode == MeasureSpec.EXACTLY) {  
        width = widthSize;  
    } else {  
        mPaint.setTextSize(mTitleTextSize);  
        mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);  
        float textWidth = mBounds.width();  
        int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());  
        width = desired;  
    }  
  
    if (heightMode == MeasureSpec.EXACTLY){  
        height = heightSize;  
    } else {  
        mPaint.setTextSize(mTitleTextSize);  
        mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);  
        float textHeight = mBounds.height();  
        int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());  
        height = desired;  
    }  
  
    setMeasuredDimension(width, height);  
}      

布局修改一下

<com.yydcdut.CustomTitleView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        custom:titleText="3712"  
        android:padding="10dp"  
        custom:titleTextColor="#ff0000"  
        android:layout_centerInParent="true"  
        custom:titleTextSize="40sp" />      
Android -- 自定義View

我是天王蓋地虎的分割線

參考:http://blog.csdn.net/lmj623565791/article/details/24252901

作者:我愛物聯網

出處:http://yydcdut.cnblogs.com/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。