正常情况下TextView的文本内容是水平显示的,那如何做到让内容垂直显示呢,于是做了一些尝试,自定义控件继承TextView,重写onDraw函数,代码如下:
@Override protected void onDraw(Canvas canvas) { canvas.rotate(-90); canvas.translate(-getHeight(), 0); super.onDraw(canvas); }
以上实现确实做到了让内容垂直显示,但是存在宽度与高度无法适配的问题,比如在指定宽度的情况下,垂直显示的文字可能会换行,这并不是我想要的结果。后来查到网上一位朋友的文章,正好解决了此问题,在此向大神致敬。做了一些整理与修改后,最终代码如下:
package com.example.sportdemo; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint.Align; import android.graphics.Path; import android.graphics.Rect; import android.text.TextPaint; import android.util.AttributeSet; import android.view.View; public class VerticalTextView extends View { private final static int DEFAULT_TEXT_SIZE = 18; private final static int DEFAULT_TEXT_COLOR = 0x00000000; private final static int DIRECTION_TTB = 0; private final static int DIRECTION_BTT = 1; private String mText = "H"; private TextPaint mTextPaint = new TextPaint(); private Rect mTextRect = new Rect(); private Path path = new Path(); private int mDirection; public VerticalTextView(Context context) { super(context); init(); } public VerticalTextView(Context context, AttributeSet attrs) { super(context, attrs); init(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerticalTextView); CharSequence text = a.getString(R.styleable.VerticalTextView_text); if (text != null) { mText = text.toString(); } int textSize = a.getDimensionPixelOffset(R.styleable.VerticalTextView_textSize, DEFAULT_TEXT_SIZE); if (textSize > 0) { mTextPaint.setTextSize(textSize); } int textColor = a.getColor(R.styleable.VerticalTextView_textColor, DEFAULT_TEXT_COLOR); mTextPaint.setColor(textColor); mDirection = a.getInt(R.styleable.VerticalTextView_direction, DIRECTION_BTT); a.recycle(); } @SuppressLint("NewApi") private final void init() { if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) { setLayerType(View.LAYER_TYPE_SOFTWARE, null); } mTextPaint.setAntiAlias(true); mTextPaint.setTextSize(DEFAULT_TEXT_SIZE); mTextPaint.setColor(DEFAULT_TEXT_COLOR); mTextPaint.setTextAlign(Align.CENTER); } public void setText(String text) { mText = text; requestLayout(); invalidate(); } public void setText(int resId) { mText = getContext().getResources().getText(resId).toString(); requestLayout(); invalidate(); } public void setTextSize(int size) { mTextPaint.setTextSize(size); requestLayout(); invalidate(); } public void setTextColor(int color) { mTextPaint.setColor(color); invalidate(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mTextPaint.getTextBounds(mText, 0, mText.length(), mTextRect); setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); } private int measureWidth(int measureSpec) { int width = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { width = specSize; } else { // width = mTextRect.height() + getPaddingLeft() + getPaddingRight(); width = mTextRect.height(); if (specMode == MeasureSpec.AT_MOST) { width = Math.min(width, specSize); } } return width; } private int measureHeight(int measureSpec) { int height = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { height = specSize; } else { // height = mTextRect.width() + getPaddingTop() + getPaddingBottom(); height = mTextRect.width(); if (specMode == MeasureSpec.AT_MOST) { height = Math.min(height, specSize); } } return height; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int startX = 0; int startY = 0; int stopY = getHeight(); if (mDirection == DIRECTION_TTB) { startX = (getWidth() >> 1) - (mTextRect.height() >> 1); path.moveTo(startX, startY); path.lineTo(startX, stopY); } else { startX = (getWidth() >> 1) + (mTextRect.height() >> 1); path.moveTo(startX, stopY); path.lineTo(startX, startY); } canvas.drawTextOnPath(mText, path, 0, 0, mTextPaint); } }
Xml布局文件:
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" > <com.example.sportdemo.VerticalTextView xmlns:demo="http://schemas.android.com/apk/res/com.example.sportdemo" android:id="@+id/vtv" android:layout_width="40dp" android:layout_height="120dp" android:background="@color/black" demo:text="helloworld" demo:textColor="@color/white" demo:textSize="20sp" demo:direction="bottomtotop" /> </LinearLayout>
这里需要强调的是,drawTextOnPath在4.1以前的系统在开启硬件加速的情况下达不到我们想要的效果,结果就是绘制的文字不显示,因此通过以下代码禁用硬件加速。
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) { setLayerType(View.LAYER_TYPE_SOFTWARE, null); }
纯属学习笔记,欢迎指正。