TextView中英文排版混乱

来源:互联网 发布:京东java面试经验 编辑:程序博客网 时间:2024/06/05 15:00

TextView问题由来

TextView在中英文夹杂的时候,会出现自动断行的情况,相信许多人都碰见过。这是系统的一个Bug,在Android5.0以后被修复了,而5.0以下的还没有见到比较好的解决版本。
参考了网上的方法,有的朋友推荐使用全角和半角转换(没有解决问题),也有的推荐了JustifyTextView这个控件(效果也不理想)
于是我决定自定义一个TextView来做这件事,勉强解决了问题,但是代价是失去了很多TextView自身拥有的特性,而且TextView自身做了很多缓存和优化的工作,Google强烈不建议我们去修改这个控件
我们先来看看实现效果:


第1行:原生TextView 全是中文
第2行:原生TextView 全是英文
第3行:原生TextView,使用全角半角转换中英文夹杂
第4行:原生TextView 中英文夹杂
第5行:JustifyTextView 中英文夹杂
第6行:原生AdaptableTextView 中英文夹杂


怎么解决?

1、将text分割成多行

思路的第一步,就是将我们要设置的文本,例如”中英文夹杂testtesttesttesttesttesttesttesttesttest”这个String分割成多行保存在一个ArrayList()中。
我们可以首先获得TextView的宽度,然后根据这个宽度,把上面的String切割成多段。
由于“我”这个中文的在绘制时候,宽度比单个英文字母,例如是”m”大。所以我们一定要遍历每个字符,获得它的宽度。

/**         * 根据控件宽度,计算得出每行的字符串         */        private void parseText(){            strs.clear();            int start = 0;//行起始Index            int curLineWidth = 0;//当前行宽            for (int i = 0; i < mText.length(); i++) {                char ch = mText.charAt(i);//获取当前字符                float[] widths = new float[1];                String srt = String.valueOf(ch);                mPaint.getTextWidths(srt, widths);//获取这个字符的宽度                if (ch == '\n'){//如果是换行符,则当独一行                    strs.add(mText.substring(start, i));                    start = i + 1;                    curLineWidth = 0;                }else{                    curLineWidth += (int) (Math.ceil(widths[0]));//计算当前宽度                    if (curLineWidth > mLineWidth){//直到当前行宽度大于控件宽度,截取为一行                        strs.add(mText.substring(start, i));                        start = i;                        i--;                        curLineWidth = 0;                    }else{                        if (i == (mText.length() - 1)){//剩余的单独一行                            strs.add(mText.substring(start, mText.length()));                        }                    }                }            }        }

2、使用drawText()方法,绘制出每一行

在上面的方法以后,我们就获得了每一行字符串了,剩下的工作就是用drawText()把每一行都绘制出来就可以了。另外还要注意一些,例如如果超出了maxLines,我们可以手动绘制一个省略号;还有padding的设置问题。

public void draw(Canvas canvas) {            int lines = mMaxLines > 0 && mMaxLines <= strs.size() ? mMaxLines : strs.size();            for (int i = 0; i < lines; i++) {                String text = strs.get(i);                //如果是最大行的最后一行但不是真实的最后一行则自动添加省略号                if(i == lines - 1 && i < strs.size() - 1)                    text = text.substring(0, text.length() - 3) + "...";                canvas.drawText(text, getPaddingLeft(), getPaddingTop()+mPaint.getTextSize() + mLineHeight * i, mPaint);            }        }

3、重写TextView的onDraw()方法

简单来说,只要在ondraw()方法里面,调用我们自定义的draw()方法,绘制出文本即可。

@Override    @SuppressLint("NewApi")    protected void onDraw(Canvas canvas) {        getAdaptableText();        if(mIsDirty) {            mIsDirty = false;            String text = getText().toString();            int maxLines = getMaxLines();            if(!mAdaptableText.getText().equals(text))                mAdaptableText.setText(text);            if(mAdaptableText.getMaxLines() != maxLines)                mAdaptableText.setMaxLines(maxLines);        }        mAdaptableText.draw(canvas);    }



写在最后

TextView的这个Bug,几乎在所有的app都存在(微信什么的),也就可以看出,貌似没有很好的解决方法
如果使用上面的自定义控件,看似解决了问题,其实带来TextView效率的严重下降,所有也强烈不建议在项目之中使用它(如果你们的app不追求效率又是另外一回事了)。

下载源码

3 0
原创粉丝点击