Android 自定義TextView 自動換行

Android TextView默認是標點符號不能再行尾和行首,英文單詞不能拆分;


1、網上有說修改源碼(表示我是菜鳥)、也有說轉半角或全角(這種真的不太行啊,半角的話還是有點問題;全角的話英文就難看了,顯示出來只能呵呵~~。)

2、自定義(我是還是很贊同的),下面是我看了網上別人的自定義代碼寫出來的(不喜勿噴),先上代碼:

/**
 * Created by wmi01 on 2015/11/23.
 * 文字排版自動換行
 */
public class ComposeTextView extends View {
    // 總高度、寬度
    private int sumHeight = 0;
    private int maxWidth = 0;
    // 一些屬性
    private int textColor = getResources().getColor(android.R.color.black);
    private int textSize = 14;
    private int lineSpace = 5;  //行間距
    private int typeFace = 0;
    private String text = "";
    private int maxLine = Integer.MAX_VALUE; //最大行數
    // 上下左右的距離
    private int left_Margin = 10;
    private int right_Margin = 10;
    private int top_Margin = 10;
    private int bottom_Margin = 10;

    private Paint mPaint;

    public ComposeTextView(Context context) {
        super(context);
    }

    public ComposeTextView(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
        DisplayMetrics dm = getResources().getDisplayMetrics();
        //爲屬性定義單位
        textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, textSize, dm);
        lineSpace = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, lineSpace, dm);
        left_Margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, left_Margin, dm);
        right_Margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, right_Margin, dm);
        top_Margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, top_Margin, dm);
        bottom_Margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, bottom_Margin, dm);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ComposeTextView);
        textSize = a.getDimensionPixelSize(R.styleable.ComposeTextView_textSize, textSize);
        textColor = a.getColor(R.styleable.ComposeTextView_textColor, textColor);
        lineSpace = a.getDimensionPixelSize(R.styleable.ComposeTextView_lineSpace, lineSpace);
        maxLine = a.getInt(R.styleable.ComposeTextView_maxLine, maxLine);
        typeFace = a.getInt(R.styleable.ComposeTextView_typeFace, typeFace);
        left_Margin = a.getDimensionPixelSize(R.styleable.ComposeTextView_left_Margin, left_Margin);
        right_Margin = a.getDimensionPixelSize(R.styleable.ComposeTextView_right_Margin, right_Margin);
        top_Margin = a.getDimensionPixelSize(R.styleable.ComposeTextView_top_Margin, top_Margin);
        bottom_Margin = a.getDimensionPixelSize(R.styleable.ComposeTextView_bottom_Margin, bottom_Margin);
        a.recycle();

        int width = dm.widthPixels;
        maxWidth = width - left_Margin - right_Margin;

        mPaint = new Paint();
        mPaint.setAntiAlias(true);// 抗鋸齒
        mPaint.setColor(textColor);
        mPaint.setTextSize(textSize);
        switch (typeFace) {
            case 0:
                mPaint.setTypeface(Typeface.DEFAULT);
                break;
            case 1:
                mPaint.setTypeface(Typeface.SANS_SERIF);
                break;
            case 2:
                mPaint.setTypeface(Typeface.SERIF);
                break;
            case 3:
                mPaint.setTypeface(Typeface.MONOSPACE);
                break;
            default:
                mPaint.setTypeface(Typeface.DEFAULT);
                break;
        }
    }

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

        int lineWidth = 0;  //字符串所佔行寬
        int lineHeight = 0; //行高
        int lineNum = 0;    //總行數
        int start = 0;      //定位:用於截取字符串
        char ch;
        int x = 0;
        int y = 30; //爲了讓文字可以顯示出來,不至於被遮蓋,特別是第一行,這個值要根據字體大小設置,可以設置一個值用來動態控制。

        Vector<String> mString = new Vector<String>();
        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        lineHeight = (int) (Math.ceil(fontMetrics.descent - fontMetrics.top) + lineSpace);
//		y += Math.ceil(fontMetrics.descent);
        for (int i = 0; i < text.length(); i++) {
            ch = text.charAt(i);
            String str = String.valueOf(ch);
            float widths[] = new float[1];
            mPaint.getTextWidths(str, widths);

            if (ch == '\n') {
                lineNum++;
                mString.addElement(text.substring(start, i));
                start = i + 1;
                lineWidth = 0;
            } else {
                lineWidth += Math.ceil(widths[0]);
                if (lineWidth > maxWidth) {
                    lineNum++;
                    mString.addElement(text.substring(start, i));
                    start = i;
                    i--;
                    lineWidth = 0;
                } else {
                    if (i == text.length() - 1) {
                        lineNum++;
                        mString.addElement(text.substring(start, text.length()));
                    }
                }
            }
            //判斷行數是否大於最大行數
            if (lineNum > maxLine) {
                lineNum = lineNum < maxLine ? lineNum : maxLine;
                float dotWidths[] = new float[3];
                String dot = "...";
                mPaint.getTextWidths(dot, dotWidths);
                int dotWidth = 0;
                for (int j = 0; j < 3; j++) {
                    dotWidth += Math.ceil(dotWidths[j]);
                }

                String string = (String) mString.elementAt(lineNum - 1);
                lineWidth = 0;
                for (int j = string.length() - 1; j >= 0; j--) {
                    float stringWidths[] = new float[j + 1];
                    String stringSub = string.substring(0, j + 1);
                    mPaint.getTextWidths(stringSub, stringWidths);
                    for (int k = 0; k < stringSub.length(); k++) {
                        lineWidth += Math.ceil(stringWidths[k]);
                    }
                    if (lineWidth + dotWidth <= maxWidth) {
                        while (mString.size() > lineNum - 1) {
                            mString.remove(mString.size() - 1);
                        }
                        mString.addElement(stringSub + dot);
                        break;
                    }
                    lineWidth = 0;
                }
                break;
            }
        }
        sumHeight = lineHeight * lineNum - lineSpace;
        for (int i = 0; i < lineNum; i++) {
            //其實設置y的只就是爲了迎合這個函數,要是不清楚可以自己百度一下
            canvas.drawText((String) mString.elementAt(i), x, y + lineHeight
                    * i, mPaint);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int measuredWidth = measuredWidth(widthMeasureSpec);
        int measuredHeight = measuredHeight(heightMeasureSpec);
        this.setMeasuredDimension(measuredWidth, measuredHeight);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                measuredWidth, measuredHeight);
        params.topMargin = top_Margin;
        params.bottomMargin = bottom_Margin;
        params.leftMargin = left_Margin;
        params.rightMargin = right_Margin;
        this.setLayoutParams(params);
    }

    private int measuredHeight(int heightMeasureSpec) {
        int specMode = MeasureSpec.getMode(heightMeasureSpec);
        int specSize = MeasureSpec.getSize(heightMeasureSpec);
        initHeight();
        // Default size if no limits specified.
        int result = sumHeight;
        if (specMode == MeasureSpec.AT_MOST) {
            result = specSize;
        } else if (specMode == MeasureSpec.EXACTLY) {
            result = sumHeight;
        }
        return result;
    }

    /**
     * 初始化高度
     */
    private void initHeight() {
        int lineHeight = 0;
        int lineNum = 0;
        int lineWidth = 0;

        FontMetrics fontMetrics = mPaint.getFontMetrics();
        lineHeight = (int) (Math.ceil(fontMetrics.descent - fontMetrics.top) + lineSpace);
        for (int i = 0; i < text.length(); i++) {
            char ch = text.charAt(i);
            String str = String.valueOf(ch);
            float widths[] = new float[1];
            mPaint.getTextWidths(str, widths);

            if (ch == '\n') {
                lineNum++;
                lineWidth = 0;
            } else {
                lineWidth += Math.ceil(widths[0]);
                if (lineWidth > maxWidth) {
                    lineNum++;
                    i--;
                    lineWidth = 0;
                } else {
                    if (i == text.length() - 1) {
                        lineNum++;
                    }
                }
            }
            if (lineNum > maxLine) {
                lineNum = lineNum < maxLine ? lineNum : maxLine;
                break;
            }
        }
        sumHeight = lineNum * lineHeight - lineSpace;
    }

    private int measuredWidth(int heightMeasureSpec) {
        int specMode = MeasureSpec.getMode(heightMeasureSpec);
        int specSize = MeasureSpec.getSize(heightMeasureSpec);
        // Default size if no limits specified.
        int result = maxWidth;
        if (specMode == MeasureSpec.AT_MOST) {
            result = specSize;
        } else if (specMode == MeasureSpec.EXACTLY) {
            result = maxWidth;
        }
        return result;
    }

    public int getTextColor() {
        return textColor;
    }

    public void setTextColor(int textColor) {
        this.textColor = textColor;
    }

    public int getTextSize() {
        return textSize;
    }

    public void setTextSize(int textSize) {
        this.textSize = textSize;
    }

    public int getLineSpace() {
        return lineSpace;
    }

    public void setLineSpace(int lineSpace) {
        this.lineSpace = lineSpace;
    }

    public int getTypeFace() {
        return typeFace;
    }

    public void setTypeFace(int typeFace) {
        this.typeFace = typeFace;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public int getLeft_Margin() {
        return left_Margin;
    }

    public void setLeft_Margin(int left_Margin) {
        this.left_Margin = left_Margin;
    }

    public int getRight_Margin() {
        return right_Margin;
    }

    public void setRight_Margin(int right_Margin) {
        this.right_Margin = right_Margin;
    }

    public int getTop_Margin() {
        return top_Margin;
    }

    public void setTop_Margin(int top_Margin) {
        this.top_Margin = top_Margin;
    }

    public int getBottom_Margin() {
        return bottom_Margin;
    }

    public void setBottom_Margin(int bottom_Margin) {
        this.bottom_Margin = bottom_Margin;
    }

    public int getMaxLine() {
        return maxLine;
    }

    public void setMaxLine(int maxLine) {
        this.maxLine = maxLine;
    }

}

在attrs.xml中

 <!-- 自定義TextView換行-->
    <declare-styleable name="ComposeTextView">
        <attr name="textColor" format="color|reference" />
        <attr name="textSize" format="dimension" />
        <attr name="lineSpace" format="dimension" />
        <attr name="maxLine" format="integer" />
        <attr name="typeFace">
            <enum name="normal" value="0" />
            <enum name="sans" value="1" />
            <enum name="serif" value="2" />
            <enum name="monospace" value="3" />
        </attr>
        <attr name="left_Margin" format="dimension" />
        <attr name="right_Margin" format="dimension" />
        <attr name="top_Margin" format="dimension" />
        <attr name="bottom_Margin" format="dimension" />
    </declare-styleable>

然後在代碼中的應用:

<com.example.ui.views.ComposeTextView
            android:id="@+id/tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style="@style/base_text_desc_style"/>


style的代碼:(注意自定義屬性在style中的使用)

<style name="base_text_desc_style">
        <item name="com.example.ui:textSize">16sp</item>
        <item name="com.example.ui:typeFace">sans</item>
        <item name="com.example.ui:maxLine">5</item>
        <item name="com.example.ui:lineSpace">5dp</item>
        <item name="com.example.ui:textColor">#333333</item>
    </style>

在Activity中的使用:

public class MainActivity extends FragmentActivity {

    String text = "Android是一種基於Linux的自由及開放源代碼的操作系統,主要使用於移動設備,如智能手機和平板電腦,由Google公司和開放手機聯盟領導及開發。尚未有統一中文名稱,中國大陸地區較多人使用“安卓”或“安致”。Android操作系統最初由Andy Rubin開發,主要支持手機。2005年8月由Google收購注資。2007年11月,Google與84家硬件製造商、軟件開發商及電信營運商組建開放手機聯盟共同研發改良Android系統。隨後Google以Apache開源許可證的授權方式,發佈了Android的源代碼。第一部Android智能手機發佈於2008年10月。Android逐漸擴展到平板電腦及其他領域上,如電視、數碼相機、遊戲機等。2011年第一季度,Android在全球的市場份額首次超過塞班系統,躍居全球第一。 2013年的第四季度,Android平臺手機的全球市場份額已經達到78.1%。[1]  2013年09月24日谷歌開發的操作系統Android在迎來了5歲生日,全世界採用這款系統的設備數量已經達到10億臺。";
    protected ComposeTextView composeTextView;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        composeTextView = (ComposeTextView) findViewById(R.id.tv);
        composeTextView.setText(text);
    }
}


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