Android 自己畫View -- drawable.draw 以及 drawText

今天遇到一個要自己畫View的問題,  其實可以通過多個View 組合來實現, 但是不是太好, 於是就自己畫了
效果圖如下:


其實可以一個ImageView  在加TextView TranslationY來解決
用translation來解決的畫, 需要自己設置 minHeight, 防止 移動的過程中 TextView被移到外面去了看不見

ok 下面來說說, 自己畫的畫 該怎麼解決,
很明顯, 需要畫一個圖片 和一個 Text
1. 畫圖 Drawable.draw(canvas);
     需要注意的是,  我們的設計給了兩個狀態的圖,  一個是按壓狀態下的一個是正常狀態下得.
     所以我們在獲取Drawable 的是時候 轉成BitMapDrawable 再來獲取bitmap 是不可取的.
     其實drawable 它本身有一個 draw 方法, 只要我們調用 setBounds 設置範圍, 在調用draw 方法就可以直接畫了
2. 畫 Text 
void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) 
x 代表  左上角頂點位置 x座標
y 代表的是 基準線的位置,  注意這不是左上角頂點y座標
所以在 drawText的時候需要注意 位置的問題

ok 下面直接上代碼: 
public class ImgWithNumTipsView extends View {
    public static final String TAG = "IconImgWithTipNumView";

    public ImgWithNumTipsView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttr(attrs);
        initView();
    }

    public ImgWithNumTipsView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttr(attrs);
        initView();
    }

    private int mTipsTextColor;
    private int mImgScrId;
    private int mTipsNum;
    private int mTipsTextSize;
    private int textMarginLeftSize;

    private Drawable mDrawable;
    private Paint mTxtPain;
    private String mTipsString;

    private void initAttr(AttributeSet attrs) {
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ImageNumTipsView);
        mTipsTextColor = typedArray.getColor(R.styleable.ImageNumTipsView_numTipsTextColor, 0XFFFFFFFF);
        mImgScrId = typedArray.getResourceId(R.styleable.ImageNumTipsView_imgSrc, -1);

        int defaultTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 11, getResources().getDisplayMetrics());
        int defaultMarginLeftSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics());

        mTipsTextSize = typedArray.getDimensionPixelSize(R.styleable.ImageNumTipsView_numTipsTextSize, defaultTextSize);
        textMarginLeftSize = typedArray.getDimensionPixelSize(R.styleable.ImageNumTipsView_numTipsTextMarginLeft, defaultMarginLeftSize);

        mTipsNum = typedArray.getInt(R.styleable.ImageNumTipsView_numTipsText, 10);
        mTipsString = mTipsNum + "";

        if (mImgScrId == -1) {
            throw new RuntimeException("ImgScrId is error");
        }
    }

    private void initView() {
        mTxtPain = new Paint();
        mTxtPain.setColor(mTipsTextColor);
        mTxtPain.setFlags(Paint.ANTI_ALIAS_FLAG);
        mTxtPain.setTextSize(mTipsTextSize);
        setDrawable(getResources().getDrawable(mImgScrId));
    }

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

        int textLeft = mDrawable.getIntrinsicWidth() + textMarginLeftSize;
        int textTop = 0;
        int textRight = textLeft + getStringWidth(mTipsString);
        int textBottom = getStringHeight();

        Rect textRect = new Rect(textLeft, textTop, textRight, textBottom);
        Paint.FontMetricsInt fontMetrics = mTxtPain.getFontMetricsInt();
        int baseline = (textRect.bottom + textRect.top - fontMetrics.bottom - fontMetrics.top) / 2;

        canvas.drawText(mTipsString, textLeft, baseline, mTxtPain);
    }

    private int getStringWidth(String str) {
        return (int) mTxtPain.measureText(str);
    }

    private int getStringHeight() {
        Paint.FontMetrics fr = mTxtPain.getFontMetrics();
        return (int) Math.ceil(fr.descent - fr.top) + 2;  //ceil() 函數向上舍入爲最接近的整數。
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = getStringWidth(mTipsString) + mDrawable.getIntrinsicWidth() + textMarginLeftSize;
        int heightSize = getStringHeight() / 2 + mDrawable.getIntrinsicWidth();

        widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.AT_MOST);
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
    }

    public int getTipsNum() {
        return mTipsNum;
    }

    public void setTipsNum(int tipsNum) {
        mTipsNum = tipsNum;
        if (mTipsNum < 999) {
            mTipsString = "" + tipsNum;
        } else {
            mTipsString = "999+";
        }
        requestLayout();
    }

    public void setTipsText(String text) {
        mTipsString = text;
        requestLayout();
        requestLayout();
    }

    public void setTipsTextColor(int color) {
        mTipsTextColor = color;
        mTxtPain.setColor(color);
        invalidate();
    }

    /**
     * @param sizePx 像素爲單位
     */
    public void setTipsTextSize(int sizePx) {
        mTipsTextSize = sizePx;
        mTxtPain.setTextSize(sizePx);
        requestLayout();
    }

    public void setDrawable(Drawable drawable) {
        mDrawable = drawable;
        Rect drawableRect = new Rect(0, getStringHeight() / 2, mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight() + getStringHeight() / 2);
        mDrawable.setBounds(drawableRect);
        requestLayout();
    }

}

一些總結:
mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight() 可以獲得 drawable的真實高度
mTxtPain.measureText(str); 可以獲取 畫出來的 字符串的寬度

Paint.FontMetrics fr = mTxtPain.getFontMetrics();
Math.ceil(fr.descent - fr.top) + 2;  //可以獲得 話來着的Text 所佔的高度

invalidate(); 會重畫, 但是不會重新佈局, 不會重新測量
requestLayout(); 會重新佈局, 重新測量

普通圖片的drawable 可以強轉成 bitmapDrawable 
selector 的drawable不可以, 他不是 bitmapDrawable

mTxtPain.setFlags(Paint.ANTI_ALIAS_FLAG);// 設置抗鋸齒
mTxtPain.setTextSize(mTipsTextSize);// 這裏設置的 像素大小, 不是 sp

關於 DrawText 的一些文章:
Drawable、Bitmap、Canvas和Paint的關係以及部分使用方法

Android Canvas drawText相關:


















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章