您的位置:首页 > 移动开发 > Android开发

Android实际开发问题10_自定义TextBasicView

2016-05-27 16:09 543 查看
代码已经上传github(github会不定期上传各种初步研究的自定义view)

GIthub地址:https://github.com/EveSum/cView

之所以要重新设计一个Textview,是因为有的时候我们仅仅只需要一个简单的Textview,不需要多复杂的,这样节省内存资源,而且还可以从中学会如何绘制各种view

绘制单行文本使用canvas.drawText

绘制多行文本使用StaticLayout.

文字的距离Paint.FontMetricsInt

package com.caoxide.cutils.component;

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.text.Layout;

import android.text.StaticLayout;

import android.text.TextPaint;

import android.util.AttributeSet;

import android.util.TypedValue;

import android.view.View;

import com.caoxide.cutils.R;

/**

 * @author cxd

 * @ClassName: com.caoxide.cutils.component

 * @Description: 自定义文本控件

 * @date 2016/5/26

 */

public class TextBasicView extends View {

    //文本

    private String cText;

    //文本颜色

    private int cTextColor;

    //文本大小

    private int cTextSize;

    //文本对齐方式

    private int cTextAligin;

    //类型

    private int lineType;

    //画笔

    private Paint mPaint;

    //画笔距离

    private Paint.FontMetricsInt anInt;

    //文本画笔(仅在lineType==3时有效)

    private TextPaint textPaint;

    //多行容器(仅在lineType==3时有效)

    private StaticLayout staticLayout;

    public TextBasicView(Context context) {

        super(context);

        init(null, 0);

    }

    public TextBasicView(Context context, AttributeSet attrs) {

        super(context, attrs);

        init(attrs, 0);

    }

    public TextBasicView(Context context, AttributeSet attrs, int defStyleAttr) {

        super(context, attrs, defStyleAttr);

        init(attrs, defStyleAttr);

    }

    /**

     * 初始化

     *

     * @param attrs

     * @param defStyleAttr

     */

    private void init(AttributeSet attrs, int defStyleAttr) {

        //获得属性

        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.TextBasicView, defStyleAttr, 0);

        //获取文本

        cText = typedArray.getString(R.styleable.TextBasicView_cText);

        //获取颜色值

        cTextColor = typedArray.getColor(R.styleable.TextBasicView_cTextColor, Color.BLUE);

        //获取字体大小

        cTextSize = typedArray.getDimensionPixelSize(R.styleable.TextBasicView_cTextSize,

                (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));

        //获取文本对齐方式

        cTextAligin = typedArray.getInt(R.styleable.TextBasicView_cTextAlign, 1);

        //获取行数类型

        lineType = typedArray.getInt(R.styleable.TextBasicView_lineType, 3);

        //记住属性

        typedArray.recycle();

        initPaint();

    }

    /**

     * 初始化画笔

     */

    private void initPaint() {

        if (lineType == 3) {

            if (textPaint == null) {

                textPaint = new TextPaint();

                //设置画笔大小

                textPaint.setTextSize(cTextSize);

                //设置画笔颜色

                textPaint.setColor(cTextColor);

            }

        } else {

            if (mPaint == null) {

                mPaint = new Paint();

                //设置画笔大小

                mPaint.setTextSize(cTextSize);

                //设置画笔颜色

                mPaint.setColor(cTextColor);

                //设置文本方向

                mPaint.setTextAlign(cTextAligin == 1 ? Paint.Align.LEFT : cTextAligin == 2 ? Paint.Align.RIGHT : Paint.Align.CENTER);

            }

            if (anInt == null) {

                anInt = mPaint.getFontMetricsInt();

            }

        }

    }

    /**

     * 获取多行布局

     *

     * @return

     */

    private StaticLayout getStaticLayout() {

        if (staticLayout == null) {

            staticLayout = new StaticLayout(cText, textPaint, getWidth() - getPaddingLeft() - getPaddingRight(),

                    cTextAligin == 1 ? Layout.Alignment.ALIGN_NORMAL : cTextAligin == 2 ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_CENTER,

                    1.2f, 0, false);

        }

        return staticLayout;

    }

    @Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        initPaint();

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);

        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int width;

        int height;

        //获取控件宽度

        if (widthMode == MeasureSpec.EXACTLY) {

            width = widthSize;

        } else {

            float showTextLength = mPaint.measureText(cText);

            width = Math.min((int) showTextLength, widthSize);

        }

        if (heightMode == MeasureSpec.EXACTLY) {

            height = heightSize;

        } else {

            if (lineType == 1) {//单行显示

                height = anInt.bottom - anInt.ascent + getPaddingTop() + getPaddingBottom();

            } else if (lineType == 2) {//两行显示

                height = 2 * anInt.bottom - anInt.ascent - anInt.top + getPaddingTop() + getPaddingBottom();

            } else {//多行显示

                height = getStaticLayout().getHeight() + getPaddingBottom() + getPaddingTop();

            }

        }

        setMeasuredDimension(width, height);

    }

    @Override

    protected void onDraw(Canvas canvas) {

        initPaint();

        int width = 0;

        if (cTextAligin == 1) {

            width = getPaddingLeft();

        } else if (cTextAligin == 2) {

            width = getWidth() - getPaddingRight();

        } else {

            width = (getWidth() - getPaddingLeft() - getPaddingRight()) / 2;

        }

        if (lineType == 1) {//单行显示

            String showText = getShowText(mPaint, cText);

            //获取基准线的高度(去除文本上面的音标区域,即不使用top,使用ascent)

            int height = (getHeight() - anInt.bottom + anInt.ascent) / 2 - anInt.ascent;

            //书写文字

            canvas.drawText(showText, width, height, mPaint);

        } else if (
4000
lineType == 2) {//两行显示

            //获取第一行显示文本

            String showText1 = getShowText(mPaint, cText, false);

            //获取第一行基准线的高度

            int height1 = (getHeight() + anInt.ascent + anInt.top) / 2 - anInt.bottom - anInt.ascent;

            //书写文字

            canvas.drawText(showText1, width, height1, mPaint);

            if (showText1.length() < cText.length()) {

                String str = cText.substring(showText1.length());

                String showText2 = getShowText(mPaint, str);//获取文字区域

                //获取第二行基准线的高度

                int height2 = (getHeight() - anInt.ascent - anInt.top) / 2;

                //书写文字

                canvas.drawText(showText2, width, height2, mPaint);

            }

        } else if (lineType == 3) {//多行显示

            canvas.translate(getPaddingLeft(), getPaddingTop());

            getStaticLayout().draw(canvas);

        }

    }

    /**

     * 获取显示文本

     *

     * @param mPaint 画笔

     * @param text   要书写的文本

     * @return 显示文本

     */

    private String getShowText(Paint mPaint, String text) {

        return getShowText(mPaint, text, true);

    }

    /**

     * 获取显示文本

     *

     * @param mPaint 画笔

     * @param text   要书写的文本

     * @param isEn   是否省略

     * @return 显示文本

     */

    private String getShowText(Paint mPaint, String text, boolean isEn) {

        //获取文本显示区域

        int textRextWidth = getWidth() - getPaddingLeft() - getPaddingRight();

        //获取要书写文字的宽度

        float textWidth = mPaint.measureText(text);

        //书写文字宽度在显示区域内,直接书写即可

        if (textWidth < textRextWidth) {

            return text;

        }

        //获取省略号的宽度

        if (isEn) {

            float enWidth = mPaint.measureText("...");

            //获取除省略号的可显示区域

            textRextWidth -= enWidth;

        }

        //获取一个汉字的宽度

        float ziWidth = mPaint.measureText("字");

        //判断书写文字是否绝大部分为汉字,误差为每十个字一个不是

        if (ziWidth * text.length() <= textWidth + text.length() / 10 * ziWidth) {

            //获取显示文字宽度

            int len = (int) (textRextWidth / ziWidth);

            int dev = ((int) (textRextWidth - mPaint.measureText(text.substring(0, len - 1))));

            while (dev > ziWidth) {

                len += dev / ziWidth;

                dev = ((int) (textRextWidth - mPaint.measureText(text.substring(0, len - 1))));

            }

            return text.substring(0, len - 1) + (isEn ? "..." : "");

        } else {

            int len = (int) (textRextWidth * text.length() / textWidth);

            if (len < 1) {

                return "...";

            }

            int len_ = len - 1;

            int dev = (int) (textRextWidth - mPaint.measureText(text.substring(0, len - 1)));

            int dev_ = (int) (textRextWidth - mPaint.measureText(text.substring(0, len_ - 1)));

            while (dev > 0 || dev_ < 0) {

                if (dev > 0) {

                    int l = (int) (dev * text.length() / textWidth);

                    if (l == 0) {

                        l = 1;

                    }

                    len += l;

                    len_ = len - 1;

                } else {

                    int l = (int) (dev_ * text.length() / textWidth);

                    if (l == 0) {

                        l = 1;

                    }

                    len_ -= l;

                    len = len_ + 1;

                }

                dev = (int) (textRextWidth - mPaint.measureText(text.substring(0, len - 1)));

                dev_ = (int) (textRextWidth - mPaint.measureText(text.substring(0, len_ - 1)));

            }

            return text.substring(0, len_ - 1) + (isEn ? "..." : "");

        }

    }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: