• 當前位置:首頁 > IT技術 > 移動平臺 > 正文

    Android自定義控件(四)---實戰篇(詳解onDraw)
    2021-09-16 11:37:23

    講到這里,這個案例基本上快結束了,在繪制(onDraw)方法中,唯一的難點就是文字 基線的確定,這點請大家務必弄清楚。廢話不多說,上碼?。?!

    首先,我們先不管基不基線的,先讓文字顯示出來再說

    package com.example.mytextview;
    
    //import javax.swing.text.View;
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.util.AttributeSet;
    import android.view.View;
    
    import androidx.annotation.Nullable;
    
    public class mTextView extends View {
        //1、設置自定義屬性變量
        private int mTextSize = 16;
        private int mTextColor = Color.RED;
        private String mText;
    
        //設置文字畫筆
        private Paint textPaint;
    
        public mTextView(Context context) {
            this(context,null);
        }
    
        public mTextView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public mTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
            //2、獲取裝有自定義屬性值的數值
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.mTextView);
            //3、精確獲取自定義屬性值
            mTextSize = typedArray.getDimensionPixelSize(R.styleable.mTextView_mTextSize,mTextSize);//源碼用的這個方法,參照 TextView
            mTextColor = typedArray.getColor(R.styleable.mTextView_mTextColor,mTextColor);
            mText = typedArray.getString(R.styleable.mTextView_mText);
            //4、回收 typedArray
            typedArray.recycle();
    
            initData();
        }
    
        private void initData() {
            textPaint = new Paint();
            //抗鋸齒
            textPaint.setAntiAlias(true);
            //設置顏色
            textPaint.setColor(mTextColor);
            //設置字體大小
            textPaint.setTextSize(mTextSize);
        }
    
        //5、測量
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //獲取寬高
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int height = MeasureSpec.getSize(heightMeasureSpec);
            //獲取模式
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            //判斷 如果是 wrap_content 模式,則 布局寬高 與 字體大小和字體長度有關
            if(widthMode == MeasureSpec.AT_MOST){
                //設置文字邊界
                Rect bounds = new Rect();
                //獲取文字邊界
                textPaint.getTextBounds(mText,0,mText.length(),bounds);
                //獲取邊界寬度  ===  獲取文字寬度
                width = bounds.width();
            }
            if (heightMode == MeasureSpec.AT_MOST){
                //設置文字邊界
                Rect bounds = new Rect();
                //獲取文字邊界
                textPaint.getTextBounds(mText,0,mText.length(),bounds);
                //獲取邊界高度  ===  獲取文字高度
                height = bounds.height();
            }
            //最后設置寬高
            setMeasuredDimension(width,height);
        }
    
        //6、繪制
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //drawText 中存在四個參數分別是: 要顯示的文本,基線x方向的起始點,基線y方向的起始點,畫筆
            canvas.drawText(mText,0,getHeight(),textPaint);
        }
    }
    

    我們先來運行一遍,看看效果:

    Android自定義控件(四)---實戰篇(詳解onDraw)_基線

    顯示不全的原因是我們把寬高寫死了,把布局文件里 控件的寬高改成 wrap_content 即可:

    Android自定義控件(四)---實戰篇(詳解onDraw)_基線_02

    ?下面顯示不全,這就有關基線問題了,那我們先來看看什么是基線,怎么求,見圖:

    Android自定義控件(四)---實戰篇(詳解onDraw)_基線_03

    所以我們可以這樣求基線,代碼里有注釋,如下:

    package com.example.mytextview;
    
    //import javax.swing.text.View;
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.util.AttributeSet;
    import android.view.View;
    
    import androidx.annotation.Nullable;
    
    public class mTextView extends View {
        //1、設置自定義屬性變量
        private int mTextSize = 16;
        private int mTextColor = Color.RED;
        private String mText;
    
        //設置文字畫筆
        private Paint textPaint;
    
        public mTextView(Context context) {
            this(context,null);
        }
    
        public mTextView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public mTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
            //2、獲取裝有自定義屬性值的數值
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.mTextView);
            //3、精確獲取自定義屬性值
            mTextSize = typedArray.getDimensionPixelSize(R.styleable.mTextView_mTextSize,mTextSize);//源碼用的這個方法,參照 TextView
            mTextColor = typedArray.getColor(R.styleable.mTextView_mTextColor,mTextColor);
            mText = typedArray.getString(R.styleable.mTextView_mText);
            //4、回收 typedArray
            typedArray.recycle();
    
            initData();
        }
    
        private void initData() {
            textPaint = new Paint();
            //抗鋸齒
            textPaint.setAntiAlias(true);
            //設置顏色
            textPaint.setColor(mTextColor);
            //設置字體大小
            textPaint.setTextSize(mTextSize);
        }
    
        //5、測量
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //獲取寬高
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int height = MeasureSpec.getSize(heightMeasureSpec);
            //獲取模式
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            //判斷 如果是 wrap_content 模式,則 布局寬高 與 字體大小和字體長度有關
            if(widthMode == MeasureSpec.AT_MOST){
                //設置文字邊界
                Rect bounds = new Rect();
                //獲取文字邊界
                textPaint.getTextBounds(mText,0,mText.length(),bounds);
                //獲取邊界寬度  ===  獲取文字寬度
                width = bounds.width();
            }
            if (heightMode == MeasureSpec.AT_MOST){
                //設置文字邊界
                Rect bounds = new Rect();
                //獲取文字邊界
                textPaint.getTextBounds(mText,0,mText.length(),bounds);
                //獲取邊界高度  ===  獲取文字高度
                height = bounds.height();
            }
            //最后設置寬高
            setMeasuredDimension(width,height);
        }
    
        //6、繪制
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //drawText 中存在四個參數分別是: 要顯示的文本,基線x方向的起始點,基線y方向的起始點,畫筆
            Paint.FontMetricsInt fontMetricsInt = textPaint.getFontMetricsInt();
            //botto 為正值 top 為負值(看圖中畫的坐標系)
            int dy = (fontMetricsInt.bottom - fontMetricsInt.top)/2 - fontMetricsInt.bottom;
            int baseLine = getHeight()/2 + dy;
            canvas.drawText(mText,0,baseLine,textPaint);
        }
    }
    

    我們再來運行一把,看看效果:

    Android自定義控件(四)---實戰篇(詳解onDraw)_基線_04

    可見,我們成功了,這篇到此為止,下一篇我們將一些優化。

    本文摘自 :https://blog.51cto.com/u

    開通會員,享受整站包年服務
    国产呦精品一区二区三区网站|久久www免费人咸|精品无码人妻一区二区|久99久热只有精品国产15|中文字幕亚洲无线码