自定義View_使用canvas畫一個斜角標

很長時間沒寫技術(shù)文章了,最近一直都很忙吧趣,好不容易周末休息趁有時間寫寫文章看看書,做一個記錄總結(jié)。來看今天的效果强挫,實現(xiàn)一個傾斜角標的展示效果岔霸,先來看下效果圖。

CustomTextView.png

這個效果呢實現(xiàn)起來很簡單俯渤,喊UI幫忙切個圖往xml里一放就好呆细,但是也存在一定的弊端,比如文字失真八匠、屏幕適配等問題絮爷,所以還是代碼實現(xiàn)比較好。一開始的想法是用TextView實現(xiàn)然后旋轉(zhuǎn)45度就好了梨树,但是會有問題坑夯,具體問題自己腦補一下啦~廢話不多說,先放GitHub傳送門:https://github.com/SuperKotlin/CustomTextView

思路


1.canvas旋轉(zhuǎn)45°抡四;
2.獲取文字的高度渊涝,然后根據(jù)文字高度計算背景色高度,賦值給Paint的寬度床嫌;
3.計算出各坐標跨释,使用drawLine畫出背景色,再畫出文字厌处。

說的再多鳖谈,不如一張草圖看得方便~

示意圖.png

注:紅色區(qū)域就代表一根線段(drawLine),這是我用了一支很粗的筆畫出來的阔涉。

實現(xiàn)過程

1.先說一下缆娃,這里我是把view設(shè)置為寬高相等的正方形,這樣比較容易理解和實現(xiàn)效果瑰排。那么就在onMeasure方法中把寬高設(shè)置成了一樣的大小贯要。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    int size = width < height ? width : height;
    /**
     * 這里高度要和寬度一致,這樣才能保證效果(不考慮測量模式)
     */
    setMeasuredDimension(size, size);
}

2.在onDraw方法中椭住,獲取canvas以view中心點旋轉(zhuǎn)45度

//這里寬高一致崇渗,所以我都寫成了getWidth() ;
canvas.rotate(45, getWidth() / 2, getWidth() / 2);

3.獲取文字高度京郑,然后稍微處理一下賦值給畫背景色塊的畫筆

Paint.FontMetricsInt fontMetricsInt = mPaintText.getFontMetricsInt();
float dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
/**
 * 這里是設(shè)置文字的背景色塊的高度宅广,根據(jù)文字的高度
 */
float mTextBackGroundHeight = dy * 2 * mOffset;
mPaint.setStrokeWidth(mTextBackGroundHeight);

4.OK,接下來我們就能用畫筆在畫布上作畫了些举,從哪下手就需要精確的坐標點跟狱,我們先來畫紅色背景色部分,那么坐標(起點和終點的X户魏、Y坐標)該怎么計算呢驶臊?

坐標示意圖.png

由示意圖可知:有了起點和終點坐標那么我們就可以調(diào)用drawLine(float startX, float startY, float stopX, float stopY, Paint paint)來畫出圖中紅色的區(qū)域了挪挤,但是圖中小x該如何求呢?勾股定理即可:
首先我們可以求出view對角線的長度关翎,再減去邊長(getWidth)扛门,最后再除以2就得出x的長度了。代碼如下:

/**
 * 這里是求出背景塊的中心點Y坐標
 */
float startY = (getWidth() - mTextBackGroundHeight) / 2;
/**
 * 這里x代表畫布旋轉(zhuǎn)以后笤休,畫筆需要延伸到旋轉(zhuǎn)之前的那個點尖飞,具體請看博客介紹
 */
float x = (float) ((Math.sqrt(2 * getWidth() * getWidth()) - getWidth()) / 2);
canvas.drawLine(-x, startY, getWidth() + x, startY, mPaint);

5.最后在畫出文字,結(jié)束

//畫文字
float mTetxWidth = mPaintText.measureText(mText, 0, mText.length());
float dx = (getWidth() - mTetxWidth) / 2;
canvas.drawText(mText, dx, startY + dy, mPaintText);

完整代碼:

CustomTextView.java:

public class CustomTextView extends View {

    private Context mContext;
    private Paint mPaintText;
    private Paint mPaint;
    private String mText = "";//需要繪制的文字
    private int mTextColor;
    private float mTextSize;
    private int mTextBgColor;
    private float mOffset = 2f;//背景色的高度偏移量控制值(文字高度的mOffset倍數(shù))

    public void setmText(String mText) {
        this.mText = mText;
    }

    public void setmTextBgColor(int mTextBgColor) {
        this.mTextBgColor = mTextBgColor;
        mPaint.setColor(mTextBgColor);
    }

    public CustomTextView(Context context) {
        this(context, null);
    }

    public CustomTextView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mContext = context;

        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
        mText = array.getString(R.styleable.CustomTextView_ct_title_name);
        mTextColor = array.getColor(R.styleable.CustomTextView_ct_title_color, Color.WHITE);
        mTextSize = array.getDimension(R.styleable.CustomTextView_ct_title_size, sp2px(context, 10));
        mTextBgColor = array.getColor(R.styleable.CustomTextView_ct_title_bd_color, Color.RED);
        array.recycle();

        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(mTextBgColor);

        mPaintText = new Paint();
        mPaintText.setAntiAlias(true);
        mPaintText.setColor(mTextColor);
        mPaintText.setTextSize(mTextSize);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int size = width < height ? width : height;
        /**
         * 這里高度要和寬度一致店雅,這樣才能保證效果(不考慮測量模式)
         */
        setMeasuredDimension(size, size);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /**
         * 實現(xiàn)的原理政基,先把畫布以中心點為準旋轉(zhuǎn)45度,
         * 然后畫文字闹啦,計算文字的高度沮明,根據(jù)這個高度稍微再擴大一些做為背景條的高度,再畫背景條(一條比較粗的直線)
         */
        canvas.rotate(45, getWidth() / 2, getWidth() / 2);

        if (!TextUtils.isEmpty(mText)) {
            Paint.FontMetricsInt fontMetricsInt = mPaintText.getFontMetricsInt();
            float dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
            /**
             * 這里是設(shè)置文字的背景色塊的高度窍奋,根據(jù)文字的高度
             */
            float mTextBackGroundHeight = dy * 2 * mOffset;
            mPaint.setStrokeWidth(mTextBackGroundHeight);

            /**
             * 這里是求出背景塊的中心點Y坐標
             */
            float startY = (getWidth() - mTextBackGroundHeight) / 2;

            /**
             * 這里x代表畫布旋轉(zhuǎn)以后荐健,畫筆需要延伸到旋轉(zhuǎn)之前的那個點,具體請看博客介紹
             */
            float x = (float) ((Math.sqrt(2 * getWidth() * getWidth()) - getWidth()) / 2);
            canvas.drawLine(-x, startY, getWidth() + x, startY, mPaint);

            //畫文字
            float mTetxWidth = mPaintText.measureText(mText, 0, mText.length());
            float dx = (getWidth() - mTetxWidth) / 2;
            canvas.drawText(mText, dx, startY + dy, mPaintText);
        }
    }

    public static int sp2px(Context context, float spValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }
}

GitHub傳送門:源碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末琳袄,一起剝皮案震驚了整個濱河市江场,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌窖逗,老刑警劉巖址否,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異碎紊,居然都是意外死亡佑附,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進店門仗考,熙熙樓的掌柜王于貴愁眉苦臉地迎上來音同,“玉大人,你說我怎么就攤上這事秃嗜∪ň” “怎么了?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵痪寻,是天一觀的道長螺句。 經(jīng)常有香客問我,道長橡类,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任芽唇,我火速辦了婚禮顾画,結(jié)果婚禮上取劫,老公的妹妹穿的比我還像新娘。我一直安慰自己研侣,他們只是感情好谱邪,可當我...
    茶點故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著庶诡,像睡著了一般惦银。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上末誓,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天扯俱,我揣著相機與錄音,去河邊找鬼喇澡。 笑死迅栅,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的晴玖。 我是一名探鬼主播读存,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼呕屎!你這毒婦竟也來了让簿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤秀睛,失蹤者是張志新(化名)和其女友劉穎尔当,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琅催,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡居凶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了藤抡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侠碧。...
    茶點故事閱讀 40,567評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖缠黍,靈堂內(nèi)的尸體忽然破棺而出弄兜,到底是詐尸還是另有隱情,我是刑警寧澤瓷式,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布替饿,位于F島的核電站,受9級特大地震影響贸典,放射性物質(zhì)發(fā)生泄漏视卢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望撇簿。 院中可真熱鬧,春花似錦厢洞、人聲如沸绳锅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鳞芙。三九已至眷柔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間原朝,已是汗流浹背驯嘱。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留竿拆,地道東北人宙拉。 一個月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像丙笋,于是被迫代替她去往敵國和親谢澈。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,585評論 2 359

推薦閱讀更多精彩內(nèi)容