当前位置: 移动技术网 > IT编程>移动开发>Android > Android AutoWrapTextView中英文排版问题的解决方法

Android AutoWrapTextView中英文排版问题的解决方法

2019年07月24日  | 移动技术网IT编程  | 我要评论

空白格 杨宗纬,刘家峡都市网,100c手机

前言

最近项目有新需求,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或者通过本地进行下载:

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对移动技术网的支持。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网