自定義view控件之TextView可以包含兩種不同的字體風格

寫下這篇文章是不爲更好的去理解自定義view機制和原理。

有時候會遇到這種需求,就是一個textview有多行(大於兩行),但是隻是title和同容不一致,而第二行又需要頂格來,遇到這種情況怎麼處理呢?

下面是給出實現效果圖:



很好,這個效果圖你已經看到了,後面話不多說,直接給出重要代碼。

自定義view的 TwoStyleTextView類代碼如下:

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.util.TypedValue;
import android.view.View;

import com.xjtu.yuzhuo.twostyletextview.R;

/**
 * Created by yuzhuo on 16/9/2.
 */
public class TwoStyleTextView extends View{

    private Context context;


    /**
     * 內容一行包行多少個字符
     */
    private int rowsCount;

    /**
     * 第一行在哪處開始字符換行
     */
    private int enterofIndex;

    /**
     * 單行的高度
     */
    private float textHeight;

    /**
     * 行數
     */
    private int rows;
    /**
     * title文本
     */
    private String mTitleText;
    /**
     * title文本的顏色
     */
    private int mTitleTextColor;
    /**
     * titel文本的大小
     */
    private int mTitleTextSize;

    /**
     * content文本
     */
    private String mContentText;
    /**
     * content文本的顏色
     */
    private int mContentTextColor;
    /**
     * content文本的大小
     */
    private int mContentTextSize;

    /**
     * 繪製時控制文本繪製的範圍
     */
    private Rect mtitleBound,mcontentBound,testBound;
    private Paint mtitlePaint,mcontentPaint,testPaint;

    public TwoStyleTextView(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
        this.context = context;
    }

    public TwoStyleTextView(Context context)
    {
        this(context, null);
        this.context = context;
    }

    /**
     * 獲得我自定義的樣式屬性
     *
     * @param context
     * @param attrs
     * @param defStyle
     */
    public TwoStyleTextView(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
        this.context = context;
        /**
         * 獲得我們所定義的自定義樣式屬性
         */
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TwoStyleTextView, defStyle, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++)
        {
            int attr = a.getIndex(i);
            switch (attr)
            {
                case R.styleable.TwoStyleTextView_titleText:
                    mTitleText = a.getString(attr);
                    break;
                case R.styleable.TwoStyleTextView_titleTextColor:
                    // 默認顏色設置爲黑色
                    mTitleTextColor = a.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.TwoStyleTextView_titleTextSize:
                    // 默認設置爲16sp,TypeValue也可以把sp轉化爲px
                    mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.TwoStyleTextView_contentText:
                    mContentText = a.getString(attr);
                    break;
                case R.styleable.TwoStyleTextView_contentTextColor:
                    // 默認顏色設置爲黑色
                    mContentTextColor = a.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.TwoStyleTextView_contentTextSize:
                    // 默認設置爲16sp,TypeValue也可以把sp轉化爲px
                    mContentTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                    break;

            }

        }
        a.recycle();

        /**
         * 獲得繪製文本的寬和高
         */
        mtitlePaint = new Paint();
        mtitlePaint.setTextSize(mTitleTextSize);
        // mPaint.setColor(mTitleTextColor);
        mtitleBound = new Rect();
        mtitlePaint.getTextBounds(mTitleText, 0, mTitleText.length(), mtitleBound);

        mcontentPaint = new Paint();
        mcontentPaint.setTextSize(mContentTextSize);
        mcontentBound = new Rect();
        mcontentPaint.getTextBounds(mContentText, 0, mContentText.length(), mcontentBound);

        testPaint = new Paint();
        testPaint.setTextSize(mContentTextSize);
        testBound = new Rect();
        testPaint.getTextBounds("我,",0,"我,".length(),testBound);
    }

    @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
        {
            mtitlePaint.setTextSize(mTitleTextSize);
            mtitlePaint.getTextBounds(mTitleText, 0, mTitleText.length(), mtitleBound);
            mcontentPaint.setTextSize(mContentTextSize);
            mcontentPaint.getTextBounds(mContentText, 0, mContentText.length(), mcontentBound);
            float wordWidth = (float)testBound.width()-6;
            float textWidth = mTitleText.length()*wordWidth+mContentText.length()*wordWidth;

            int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
            if(desired%widthSize==0){
                rows = desired/widthSize;
            }else{
                rows = desired/widthSize + 1;
            }
            if(rows>1){
                rowsCount = (int)((widthSize-getPaddingLeft()*2) / wordWidth);
                enterofIndex = (int)((widthSize - mtitleBound.width())/wordWidth)-1;
            }
            width = desired<=widthSize?desired:widthSize;
        }

        if (heightMode == MeasureSpec.EXACTLY)
        {
            height = heightSize;
        } else
        {
            mtitlePaint.setTextSize(mTitleTextSize);
            mtitlePaint.getTextBounds(mTitleText, 0, mTitleText.length(), mtitleBound);
            mcontentPaint.setTextSize(mContentTextSize);
            mcontentPaint.getTextBounds(mContentText, 0, mContentText.length(), mcontentBound);
            textHeight = mtitleBound.height()>mcontentBound.height()?mtitleBound.height():mcontentBound.height();

            int desired = (int) (getPaddingTop() + textHeight*rows+ getPaddingTop()*(rows-1) + getPaddingBottom());
            height = desired<=heightSize?desired:heightSize;
        }
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        mtitlePaint.setColor(Color.TRANSPARENT);
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mtitlePaint);

        mtitlePaint.setColor(mTitleTextColor);
        mcontentPaint.setColor(mContentTextColor);
        canvas.drawText(mTitleText, getPaddingLeft(),textHeight+getPaddingTop(), mtitlePaint);
        canvas.drawText(mContentText.substring(0,enterofIndex), getPaddingLeft()*2+mtitleBound.width(),textHeight+getPaddingTop(), mcontentPaint);

        for (int i = 1;rows>1&&i<rows;i++){
            if(i == rows -1){//最後一行
                canvas.drawText(mContentText.substring(enterofIndex+(i-1)*rowsCount), getPaddingLeft(),(textHeight+getPaddingTop())*(i+1), mcontentPaint);
            }else{
                canvas.drawText(mContentText.substring(enterofIndex+(i-1)*rowsCount,enterofIndex+i*rowsCount), getPaddingLeft(),(textHeight+getPaddingTop())*(i+1), mcontentPaint);
            }
        }
    }
}

attrs.xml文件中的style代碼如下:

 <declare-styleable name="TwoStyleTextView">
        <attr name="titleText" format="string" />
        <attr name="titleTextColor" format="color"/>
        <attr name="titleTextSize" format="dimension"/>
        <attr name="contentText" format="string" />
        <attr name="contentTextColor" format="color"/>
        <attr name="contentTextSize" format="dimension"/>
    </declare-styleable>
 

佈局文件代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:twostyle="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.xjtu.yuzhuo.twostyletextview.MainActivity">

    <com.xjtu.yuzhuo.twostyletextview.view.TwoStyleTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:padding="5dp"
        twostyle:titleText="姓名:"
        twostyle:titleTextSize="18sp"
        twostyle:titleTextColor="@android:color/holo_red_light"
        twostyle:contentText="一直以爲幸福在遠方,在可以追逐的未來。後來才發現,那些擁抱過的人,握過的手、唱過的歌、流過的淚、愛過的人、所謂的曾經,就是幸福。在無數的夜裏,說過的話、打過的電話,看過的電影、流過的眼淚、看見的或看不見的感動,我們都曾經有過,然後在時間的穿梭中,一切成爲了永恆!"
        twostyle:contentTextSize="18sp"
        twostyle:contentTextColor="@android:color/holo_blue_bright"
        />
</RelativeLayout>

好了,全部都給出來了自己去試吧!

最後,如果需要項目工程的可以看github:https://github.com/yuxiaoxi/TwoStyleTextView,

謝謝大家批評指正,多點贊


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