Andriod自定義View一:TextView可設(shè)置寬高

第一步:建立一個MyCustomView繼承View,實現(xiàn)構(gòu)造方法

/**
 * Created by chenshouyin on 17/3/9.
 */

public class MyCustomView extends View {
    //1.此處應(yīng)該繼承View

    //2.此處用this依次調(diào)用第二個第三個構(gòu)造方法
    public MyCustomView(Context context) {
        //super(context);
        this(context, null);
    }

    public MyCustomView(Context context, @Nullable AttributeSet attrs) {
        //super(context, attrs);
        this(context, attrs, 0);
    }

    public MyCustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //3.此處得到attrs.xml里面,我們的自定義的樣式屬性  Attribute屬性的意思,AttributeSet那么就是xml中的屬性設(shè)置的意思
    }

}

第二步:在res資源文件夾新建atts.xml文件設(shè)置自定義View需要用到的屬性

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!--1.屬性聲明-->

    <!--此處定義了字體類型,字體大小,字體顏色,當(dāng)然還有很多其它的屬性比如View的其它屬性,如-->
    <attr name="titleText" format="string"></attr>
    <attr name="titleColor" format="color"></attr>
    <attr name="titleSize" format="dimension"></attr>

    <!--2.定義樣式-->
    <declare-styleable name="MyCustomTextViewAtts">
        <attr name="titleText"></attr>
        <attr name="titleSize"></attr>
        <attr name="titleColor"></attr>
    </declare-styleable>

</resources>

`

**第三步:布局文件中引用自定義屬性并且使用自定義屬性**
Paste_Image.png

小技巧:主要輸入custom:編譯器會自動給我們導(dǎo)入

zhu

網(wǎng)上導(dǎo)入是這樣子的

xmlns:custom="http://schemas.android.com/apk/res/hxing.com.mycustomtextview.MyCustomTextView

可能AS版本的問題,我這里會提示用

xmlns:custom="http://schemas.android.com/apk/res-auto"

csy.jpg

好了,到此,我們在布局文件也已經(jīng)引入了自定義View,那么運行程序,是不是可以看到TextView了呢?別急,我們還沒把View畫出來呢。

第四步:設(shè)置畫筆大小,顏色,字體。

  private String mTextViewString;
  private int mTextViewColor;
  private int mTextViewSize;

思考:為什么MyCustomView中已經(jīng)設(shè)置了文字,文字顏色,文字大小,還要設(shè)置畫筆大小,顏色,字體呢?

  custom:titleColor="#d41e1e"
  custom:titleSize="16sp"
  custom:titleText="我是自定義居中的View"

因為這里要獲取我們定義的屬性的值

Paste_Image.png

第三個構(gòu)造方法里面的具體設(shè)置如下:

public MyCustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //3.此處得到attrs.xml里面,我們的自定義的樣式屬性  Attribute屬性的意思,AttributeSet那么就是xml中的屬性設(shè)置的意思
        TypedArray array = context.getTheme().obtainStyledAttributes(attrs,R.styleable.MyCustomTextViewAtts,defStyleAttr,0);
        for (int i=0;i<array.getIndexCount();i++){
            //思考array.getIndexCount() 如果R.styleable.MyCustomTextViewAtts沒有屬性會怎么樣呢?
            int atts = array.getIndex(i);
            switch (atts){//注意是getIndex(i)
                case R.styleable.MyCustomTextViewAtts_titleText:
                    mTextViewString = array.getString(atts);//注意是getString(i)
                    break;
                case R.styleable.MyCustomTextViewAtts_titleSize:
                    mTextViewSize = (int)array.getDimension(atts,16);//默認16sp
                    break;
                case R.styleable.MyCustomTextViewAtts_titleColor:
                    mTextViewColor = array.getInteger(atts, Color.BLACK); //默認顏色設(shè)置為黑色
                    break;
            }
        }
        array.recycle();//回收

        //4.設(shè)置畫筆屬性
        mTextViewPaint = new Paint();
        mTextViewPaint.setTextSize(mTextViewSize);
        //mTextViewPaint.setColor(mTextViewColor);每次畫的時候需要設(shè)置顏色
        //5.設(shè)置畫布的寬高
        mTextViewBoubd = new Rect();
        //getTextBounds 由調(diào)用者返回在邊界(分配)的最小矩形包含所有的字符,以隱含原點(0,0)
        mTextViewPaint.getTextBounds(mTextViewString,0,mTextViewString.length(),mTextViewBoubd);//String text, int start, int end, Rect bounds
    }

第五步:onMeasure,我們后面再討論。

第六步:onLayout,也放在后面再討論。

第七步:onDraw。

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //5.繪制畫布大小顏色
        mTextViewPaint.setColor(Color.BLUE);
        //float left, float top, float right, float bottom, Paint paint
        //參數(shù)設(shè)置參考本人博客:http://blog.csdn.net/e_inch_photo/article/details/60978088
        canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mTextViewPaint);//畫布大小,onMeasure中測量大小

        //6.繪制文字位置,大小顏色
        mTextViewPaint.setColor(mTextViewColor);//重置畫筆顏色
        //String text, int start, int end, float x, float y, Paint paint
        //參數(shù)設(shè)置參考本人博客:http://blog.csdn.net/e_Inch_Photo/article/details/60981766
        //y是指定這個字符baseline在屏幕上的位置,參照http://www.itdecent.cn/p/f80f2f73bf3f
        Paint.FontMetricsInt fontMetrics = mTextViewPaint.getFontMetricsInt();
        int baseline = (getMeasuredHeight() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
        canvas.drawText(mTextViewString,getMeasuredWidth()/2-mTextViewBoubd.width()/2,baseline,mTextViewPaint);//文字在畫布中的位置  居中

    }

好了此時看效果圖:

效果圖1.png

但是很明顯View的寬高不符合我們的預(yù)期,設(shè)置的是

android:layout_width="wrap_content"
android:layout_height="wrap_content"

但是占據(jù)了整個屏幕。

如果設(shè)置成match_parent會怎樣呢?效果還是一樣的。

android:layout_width="match_parent"
android:layout_height="match_parent"

如果給它設(shè)置固定大小呢?

 android:layout_width="200dp"
 android:layout_height="50dp"

效果圖如下:

效果圖2.png

我這里使用的是約束布局,在父布局中居中的設(shè)置,這些都是小細節(jié)了~

    <hxing.com.mycustomtextview.MyCustomView
        android:layout_width="200dp"
        android:layout_height="50dp"
        custom:titleColor="#d41e1e"
        custom:titleSize="16sp"
        custom:titleText="我是自定義居中的View"
        custom:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        android:layout_marginRight="8dp"
        custom:layout_constraintRight_toRightOf="parent"
        custom:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginLeft="8dp"
        custom:layout_constraintHorizontal_bias="0.565"
        custom:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp"
        custom:layout_constraintVertical_bias="0.498" />

加單的自定義View已經(jīng)結(jié)束了,我們在回頭看下第五步
第五步:onMeasure

系統(tǒng)幫我們測量的高度和寬度都是MATCH_PARNET。

當(dāng)我們設(shè)置明確的寬度和高度時,系統(tǒng)幫我們測量的結(jié)果就是我們設(shè)置的結(jié)果。

當(dāng)我們設(shè)置為WRAP_CONTENT,或者MATCH_PARENT系統(tǒng)幫我們測量的結(jié)果就是MATCH_PARENT的長度。

所以,當(dāng)設(shè)置了WRAP_CONTENT時,我們需要自己進行測量,即重寫onMesure方法:

重寫之前先了解MeasureSpec的specMode,一共三種類型:
EXACTLY:一般是設(shè)置了明確的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一個最大值內(nèi),一般為WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用

我們再把布局文件中的寬高改一下,設(shè)置成

  android:layout_width="wrap_content"
  android:layout_height="wrap_content"

但是我們還是想要得到固定大小的View。

  android:layout_width="200dp"
  android:layout_height="50dp"

重寫onDraw方法

  @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        //當(dāng)View設(shè)置的不是固定大小的時候,需要測量
        int myWidth, myHeight;
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);//得到布局文件中寬高設(shè)置的類型
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthMode == MeasureSpec.EXACTLY) {//設(shè)置的固定的,如100dp,MATCH_PARENT
            myWidth = widthMeasureSpec;
        } else {//包括其他不確定的情況
            mTextViewPaint.setTextSize(mTextViewSize);
            mTextViewPaint.getTextBounds(mTextViewString, 0, mTextViewString.length(), mTextViewBoubd);
            float textWidth = mTextViewBoubd.width();//文字寬度
            myWidth = (int) (textWidth + getPaddingLeft() + getPaddingRight());//加上左右間距
        }

        //高度
        if (heightMode == MeasureSpec.EXACTLY) {//設(shè)置的固定的,如100dp,MATCH_PARENT
            myHeight = heightMeasureSpec;
        } else {//包括其他不確定的情況
            mTextViewPaint.setTextSize(mTextViewSize);
            mTextViewPaint.getTextBounds(mTextViewString, 0, mTextViewString.length(), mTextViewBoubd);
            float textHeight = mTextViewBoubd.height();//文字寬度
            myHeight = (int) (textHeight + getPaddingTop() + getPaddingBottom());//加上左右間距
        }

        setMeasuredDimension(myWidth, myHeight);//設(shè)置寬高

    }

效果圖

效果圖3.png

關(guān)于第六步:onLayout,后面再專門討論。
接下來實現(xiàn)點擊事件和更新TextView文字。

1、implements View.OnClickListener

2、setOnClickListener(this);//設(shè)置點擊事件

   
@Override
    public void onClick(View view) {
        //點擊的時候改變文字,并且重繪
        Random random = new Random();
        mTextViewString = "隨機數(shù):"+random.nextInt(100000);
        postInvalidate();//會調(diào)用onDraw方法一次
        //Android中實現(xiàn)view的更新有兩組方法,一組是invalidate,另一組是postInvalidate,
        //其中前者是在UI線程自身中使用,而后者在非UI線程中使用。
    }

接下來看效果圖:


自定義View點擊效果.gif

Github地址:
https://github.com/chenshouyin/MyCustomTextView

博客地址:
http://blog.csdn.net/e_Inch_Photo/article/details/61195762

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容