欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-12-01 11:31:58
前言 最近项目有新需求,ued给了个卡券密码的ui样式,如图: 我一看很简单啊,一个textview解决问题,然后做好以后在模拟器里一看..... 纳...

前言

最近项目有新需求,ued给了个卡券密码的ui样式,如图:

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

我一看很简单啊,一个textview解决问题,然后做好以后在模拟器里一看.....

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

纳尼,这个时候才想起来,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,然后循环文本绘制每一行文本内容。

效果图

我们来看下最后的效果

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

结束语

至此整个类的逻辑分析就结束了,想看完整源码的可以移步:https://github.com/chenpengfei88/autowraptextview或者通过本地进行下载:http://xiazai.jb51.net/201705/yuanma/autowraptextview(jb51.net).rar

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