Android AutoWrapTextView中英文排版问题的解决方法
前言
最近项目有新需求,ued给了个卡券密码的ui样式,如图:
我一看很简单啊,一个textview解决问题,然后做好以后在模拟器里一看.....
纳尼,这个时候才想起来,textview 中英文在一起会有排版问题,那怎么解决呢......
思路
刚开始的想法是一个字符一个字符的去绘制,绘制到最右边的临界点就换行绘制,结果实践以后发现不同的字符之间的间距不一样,显示会非常凌乱,又没有什么好的方案解决这个间距问题,所以这个方案pass;单个字符绘制不行那就一行一行绘制,根据view的长度把文本拆分成n行,然后一行一行的绘制。
实现
首先创建一个继承自view的autowraptextview
public class autowraptextview extends view { }
来看看它的构造方法
public autowraptextview(context context, attributeset attrs) { super(context, attrs); init(context, attrs); } private void init(context context, attributeset attrs) { initstyle(context, attrs); initpaint(); }
init方法里分别调用了initstyle方法和initpaint方法;
initstyle方法主要解析自定义的属性
private void initstyle(context context, attributeset attrs) { typedarray typedarray = context.obtainstyledattributes(attrs, r.styleable.autowraptextviewstyle); mpaddingleft = typedarray.getdimensionpixelsize(r.styleable.autowraptextviewstyle_paddingleft, 0); mpaddingright = typedarray.getdimensionpixelsize(r.styleable.autowraptextviewstyle_paddingright, 0); mpaddingtop = typedarray.getdimensionpixelsize(r.styleable.autowraptextviewstyle_paddingtop, 0); mpaddingbottom = typedarray.getdimensionpixelsize(r.styleable.autowraptextviewstyle_paddingbottom, 0); mtextcolor = typedarray.getcolor(r.styleable.autowraptextviewstyle_textcolor, color.black); mtextsize = typedarray.getdimensionpixelsize(r.styleable.autowraptextviewstyle_textsize, 50); mlinespacingextra = typedarray.getinteger(r.styleable.autowraptextviewstyle_linespacingextra, 7); typedarray.recycle(); }
属性名含义都很明显不用过多解释,initpaint方法就是初始化一个文本画笔
private void initpaint() { mtextpaint = new textpaint(); mtextpaint.setantialias(true); mtextpaint.settextsize(mtextsize); mtextpaint.setcolor(mtextcolor); mtextpaint.settextalign(paint.align.left); }
接下来我们看看设置文本的方法settext方法
public void settext(string text) { if (textutils.isempty(text)) return; //把文本转换成char数组 mtextchararray = text.tochararray(); requestlayout(); }
首先把文本转换成char数组,然后循环数组把整个文本拆分成n行文本,下面来看看核心方法splittext方法
private void splittext(int heightmode) { if (mtextchararray == null) return; msplittextlist = new arraylist<>(); msingletextwidth = getmeasuredwidth() - mpaddingleft - mpaddingright; int currentsingletextwidth = 0; stringbuffer linestringbuffer = new stringbuffer(); for (int i = 0, length = mtextchararray.length; i < length; i++) { char textchar = mtextchararray[i]; currentsingletextwidth += getsinglecharwidth(textchar); if (currentsingletextwidth > msingletextwidth) { msplittextlist.add(linestringbuffer.tostring()); linestringbuffer = new stringbuffer(); currentsingletextwidth = 0; i--; } else { linestringbuffer.append(textchar); if (i == length - 1) msplittextlist.add(linestringbuffer.tostring()); } } int textheight = 0; msplittextrectarray = new rect[msplittextlist.size()]; for (int m = 0, length = msplittextlist.size(); m < length; m++) { string linetext = msplittextlist.get(m); rect linetextrect = new rect(); mtextpaint.gettextbounds(linetext, 0, linetext.length(), linetextrect); if (heightmode == measurespec.at_most) { textheight += (linetextrect.height() + mlinespacingextra); if (m == length - 1) { textheight = textheight + mpaddingbottom + mpaddingtop; } } else { if (textheight == 0) textheight = getmeasuredheight(); } msplittextrectarray[m] = linetextrect; } setmeasureddimension(getmeasuredwidth(), textheight); }
首先创建一个属性名为msplittextlist的list集合用来存放拆分的文本;
msingletextwidth 为单行文本显示的宽度;
currentsingletextwidth 为当前一行累计计算的宽度;
然后开始循环char数组,getsinglecharwidth方法就是计算单个char的宽度;
如果currentsingletextwidth 小于 msingletextwidth 就把char添加到linestringbuffer 当中,如果是最后一个char就直接把linestringbuffer添加到msplittextlist集合当中
如果currentsingletextwidth 大于 msingletextwidth,就把linestringbuffer添加到msplittextlist集合当中,重新给linestringbuffer赋值,currentsingletextwidth 归0;
循环结束以后拆分好的文本就都添加到msplittextlist集合当中了。
拆分完成以后循环msplittextlist集合,得到每一行文本的rect值,绘制文本的时候会用到,然后设置view的宽高。
接下来就是绘制方法drawtext
public void drawtext(canvas canvas) { if (msplittextlist == null || msplittextlist.size() == 0) return; int margintop = gettoptextmargintop(); for (int m = 0, length = msplittextlist.size(); m < length; m++) { string linetext = msplittextlist.get(m); canvas.drawtext(linetext, mpaddingleft, margintop, mtextpaint); margintop += (msplittextrectarray[m].height() + mlinespacingextra); } }
首先得到第一行文本距离顶部的高度margintop,然后循环文本绘制每一行文本内容。
效果图
我们来看下最后的效果
结束语
至此整个类的逻辑分析就结束了,想看完整源码的可以移步:https://github.com/chenpengfei88/autowraptextview或者通过本地进行下载:http://xiazai.jb51.net/201705/yuanma/autowraptextview(jb51.net).rar
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。
上一篇: 软文推广如何植入广告还让人拍手称赞?
下一篇: C#动态编译并执行字符串样例
推荐阅读
-
android虚拟键盘弹出遮挡登陆按钮问题的解决方法
-
Android 解决TextView排版参差不齐的问题
-
Android滑动冲突问题的解决方法
-
Android GPS室内定位问题的解决方法(location为null)
-
Android编程中activity启动时出现白屏、黑屏问题的解决方法
-
Android编程中出现The connection to adb is down问题的解决方法
-
Android圆形头像拍照后“无法加载此图片”的问题解决方法(适配Android7.0)
-
Android滑动冲突问题的解决方法
-
Android中Splash应用启动白屏问题的解决方法
-
Android GPS室内定位问题的解决方法(location为null)