Android实现竖直显示的TextView【转载】

转载自:http://hz-chenwenbiao-91.iteye.com/blog/2089851  

感觉写的很好,特此转载记录下。但是我发现这个哥们也是转的,原文出处已经找不到在哪儿了。

public class VerticalTextView extends View {

    public static final int LAYOUT_CHANGED = 1;
    private Paint paint;
    private int mTextPosx = 0;// x坐标
    private int mTextPosy = 0;// y坐标
    private int mTextWidth = 0;// 绘制宽度
    private int mTextHeight = 0;// 绘制高度
    private int mFontHeight = 0;// 绘制字体高度
    private float mFontSize = 24;// 字体大小
    private int mRealLine = 0;// 字符串真实的行数
    private int mLineWidth = 0;//列宽度
    private int TextLength = 0;//字符串长度
    private int oldwidth = 0;//存储久的width
    private String text = "";//待显示的文字
    private Handler mHandler = null;
    private Matrix matrix;
    BitmapDrawable drawable = (BitmapDrawable) getBackground();

    public VerticalTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public VerticalTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        matrix = new Matrix();
        paint = new Paint();//新建画笔
        paint.setTextAlign(Paint.Align.CENTER);//文字居中
        paint.setAntiAlias(true);//平滑处理
        paint.setColor(Color.BLACK);//默认文字颜色
        try {
            mFontSize = Float.parseFloat(attrs.getAttributeValue(null, "textSize"));//获取字体大小属性
        } catch (Exception e) {
        }
    }

    /*
    //获取整数值
    private final int getAttributeIntValue(AttributeSet attrs,String field) {
        int intVal = 0;
        //TODO
        //应该可以直接用attrs.getAttributeIntValue()获取对应的数值的,
        //但不知道为什么一直无法获得只好临时写个函数凑合着用,没有写完整,暂时只支持px作为单位,其它单位的转换有空再写
        String tempText=attrs.getAttributeValue(androidns, field);
        intVal = (int)Math.ceil(Float.parseFloat(tempText.replaceAll("px","")));
        return intVal;
    }*/
    //设置文字
    public final void setText(String text) {
        this.text = text;
        this.TextLength = text.length();
        if (mTextHeight > 0) GetTextInfo();
    }

    //设置字体大小
    public final void setTextSize(float size) {
        if (size != paint.getTextSize()) {
            mFontSize = size;
            if (mTextHeight > 0) GetTextInfo();
        }
    }

    //设置字体颜色
    public final void setTextColor(int color) {
        paint.setColor(color);
    }

    //设置字体颜色
    public final void setTextARGB(int a, int r, int g, int b) {
        paint.setARGB(a, r, g, b);
    }

    //设置字体
    public void setTypeface(Typeface tf) {
        if (this.paint.getTypeface() != tf) {
            this.paint.setTypeface(tf);
        }
    }

    //设置行宽
    public void setLineWidth(int LineWidth) {
        mLineWidth = LineWidth;
    }

    //获取实际宽度
    public int getTextWidth() {
        return mTextWidth;
    }

    //设置Handler,用以发送事件
    public void setHandler(Handler handler) {
        mHandler = handler;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.v("TextViewVertical", "onDraw");
        if (drawable != null) {
            //画背景
            Bitmap b = Bitmap.createBitmap(drawable.getBitmap(), 0, 0, mTextWidth, mTextHeight);
            canvas.drawBitmap(b, matrix, paint);
        }
        //画字
        draw(canvas, this.text);
    }

    private void draw(Canvas canvas, String thetext) {
        char ch;
        mTextPosy = 0;//初始化y坐标
        mTextPosx = mTextWidth - mLineWidth;//初始化x坐标
        for (int i = 0; i < this.TextLength; i++) {
            ch = thetext.charAt(i);
            if (ch == '\n') {
                mTextPosx -= mLineWidth;// 换列
                mTextPosy = 0;
            } else {
                mTextPosy += mFontHeight;
                if (mTextPosy > this.mTextHeight) {
                    mTextPosx -= mLineWidth;// 换列
                    i--;
                    mTextPosy = 0;
                } else {
                    canvas.drawText(String.valueOf(ch), mTextPosx, mTextPosy, paint);
                }
            }
        }

        //调用接口方法
        //activity.getHandler().sendEmptyMessage(TestFontActivity.UPDATE);
    }

    //计算文字行数和总宽
    private void GetTextInfo() {
        Log.v("TextViewVertical", "GetTextInfo");
        char ch;
        int h = 0;
        paint.setTextSize(mFontSize);
        //获得字宽
        if (mLineWidth == 0) {
            float[] widths = new float[1];
            paint.getTextWidths("正", widths);//获取单个汉字的宽度
            mLineWidth = (int) Math.ceil(widths[0] * 1.1 + 2);
        }

        Paint.FontMetrics fm = paint.getFontMetrics();
        mFontHeight = (int) (Math.ceil(fm.descent - fm.top) * 0.9);// 获得字体高度

        //计算文字行数
        mRealLine = 0;
        for (int i = 0; i < this.TextLength; i++) {
            ch = this.text.charAt(i);
            if (ch == '\n') {
                mRealLine++;// 真实的行数加一
                h = 0;
            } else {
                h += mFontHeight;
                if (h > this.mTextHeight) {
                    mRealLine++;// 真实的行数加一
                    i--;
                    h = 0;
                } else {
                    if (i == this.TextLength - 1) {
                        mRealLine++;// 真实的行数加一
                    }
                }
            }
        }
        mRealLine++;//额外增加一行
        mTextWidth = mLineWidth * mRealLine;//计算文字总宽度
        measure(mTextWidth, getHeight());//重新调整大小
        layout(getLeft(), getTop(), getLeft() + mTextWidth, getBottom());//重新绘制容器
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int measuredHeight = measureHeight(heightMeasureSpec);
        //int measuredWidth = measureWidth(widthMeasureSpec);
        if (mTextWidth == 0) GetTextInfo();
        setMeasuredDimension(mTextWidth, measuredHeight);
        if (oldwidth != getWidth()) {//
            oldwidth = getWidth();
            if (mHandler != null) mHandler.sendEmptyMessage(LAYOUT_CHANGED);
        }
    }

    private int measureHeight(int measureSpec) {
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        int result = 500;
        if (specMode == MeasureSpec.AT_MOST) {
            result = specSize;
        } else if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        }
        mTextHeight = result;//设置文本高度
        return result;
    }
    /*
    private int measureWidth(int measureSpec) {
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        int result = 500;
        if (specMode == MeasureSpec.AT_MOST){
            result = specSize;
        }else if (specMode == MeasureSpec.EXACTLY){
            result = specSize;
        }
        return result;
    }  */
}

用法是:

public class TestFontActivity extends Activity{  
    private HorizontalScrollView sv;  
    private TextViewVertical tv;  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);  
         setContentView(R.layout.main);  
           
         tv=(TextViewVertical)findViewById(R.id.tv);    
         sv=(HorizontalScrollView)findViewById(R.id.sv);    
           
         //设置接口事件接收  
         Handler handler=new Handler(){  
            public void handleMessage(android.os.Message msg) {  
                switch(msg.what){  
                    case TextViewVertical.LAYOUT_CHANGED:  
                        sv.scrollBy(tv.getTextWidth(), 0);//滚动到最右边  
                        break;  
                }  
            }  
         };  
         tv.setHandler(handler);//将Handler绑定到TextViewVertical  
           
         //创建并设置字体(这里只是为了效果好看一些,但为了让网友们更容易下载,字体库并没有一同打包  
         //如果需要体验下效果的朋友可以自行在网络上搜索stxingkai.ttf并放入assets/fonts/中)  
         //Typeface face=Typeface.createFromAsset(getAssets(),"fonts/stxingkai.ttf");  
         //tv.setTypeface(face);  
           
         //设置文字内容  
         tv.setText("测试\n这是一段测试文字,主要是为了测试竖直排版TextView的显示效果。" +  
                "为了能更好的体验感受,我特意增加了比较接近书法的字体和颜色,如果有什么改进的建议请发邮件到我的邮箱吧。" +  
                "\n竖直排版的TextView需要配合HorizontalScrollView使用才能有更佳的效果。当然,如果你有时间的话,也可以给这个类" +  
                "加上滚动的功能。");  
    }  
  
}  

如果你觉得帮到了你,请给作者打赏一口饭吃:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值