• Android TextView自己主动换行文字排版參差不齐的原因


      今天项目没什么进展,公司后台出问题了。看了下刚刚学习Android时的笔记,发现TextView会自己主动换行,并且排版文字參差不齐。查了下资料,总结原因例如以下:

      1、半角字符与全角字符混乱所致:这样的情况一般就是汉字与数字、英文字母混用

      解决方法一:

      将textview中的字符全角化。即将所有的数字、字母及标点所有转为全角字符,使它们与汉字同占两个字节,这样就能够避免因为占位导致的排版混乱问题了。 半角转为全角的代码例如以下,仅仅需调用就可以。

      public static String ToDBC(String input) {

      char[] c = input.toCharArray();

      for (int i = 0; i< c.length; i++) {

      if (c[i] == 12288) {

      c[i] = (char) 32;

      continue;

      }if (c[i]> 65280&& c[i]< 65375)

      c[i] = (char) (c[i] - 65248);

      }

      return new String(c);

      }

      解决方法二:

      去除特殊字符或将全部中文标号替换为英文标号。利用正則表達式将全部特殊字符过滤,或利用replaceAll()将中文标号替换为英文标号。则转化之后,则可解决排版混乱问题。

      // 替换、过滤特殊字符

      public static String StringFilter(String str) throws PatternSyntaxException{

      str=str.replaceAll("【","[").replaceAll("】","]").replaceAll("!","!");//替换中文标号

      String regEx="[『』]"; // 清除掉特殊字符

      Pattern p = Pattern.compile(regEx);

      Matcher m = p.matcher(str);

      return m.replaceAll("").trim();

      }

      2、TextView在显示中文的时候 标点符号不能显示在一行的行首和行尾,假设一个标点符号刚好在一行的行尾,该标点符号就会连同前一个字符跳到下一行显示。

      解决方法:在标点符号后加一个空格。

      3、一个英文单词不能被显示在两行中( TextView在显示英文时,标点符号是能够放在行尾的,但英文单词也不能分开 )。

      4、假设要两行对其的显示效果:有两种方法

      方法一:

      改动Android源码;将frameworks/base/core/java/android/text下的StaticLayout.java文件里的例如以下代码:

      if (c == ' ' || c == '/t' ||

      ((c == '.' || c == ',' || c == ':' || c == ';') &&

      (j - 1 < here || !Character.isDigit(chs[j - 1 - start])) &&

      (j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||

      ((c == '/' || c == '-') &&

      (j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||

      (c >= FIRST_CJK && isIdeographic(c, true) &&

      j + 1 < next && isIdeographic(chs[j + 1 - start], false))) {

      okwidth = w;

      ok = j + 1;

      if (fittop < oktop)

      oktop = fittop;

      if (fitascent < okascent)

      okascent = fitascent;

      if (fitdescent > okdescent)

      okdescent = fitdescent;

      if (fitbottom > okbottom)

      okbottom = fitbottom;

      }

      去掉就能够了。去掉后标点符号能够显示在行首和行尾,英文单词也能够被分开在两行中显示。

      方法二:

      自己定义View显示文本

      网上就有达人採用自己定义View来解决问题,我做了实验并总结了一下:

      自己定义View的步骤:

      1)继承View类或其子类,样例继承了TextView类;

      2)写构造函数,通过XML获取属性(这一步中能够自己定义属性,见例程);

      3)重写父类的某些函数,一般都是以on开头的函数,样例中重写了onDraw()和onMeasure()函数;

      =========================CYTextView.java=============================

      public class CYTextView extends TextView {

      public static int m_iTextHeight; //文本的高度

      public static int m_iTextWidth;//文本的宽度

      private Paint mPaint = null;

      private String string="";

      private float LineSpace = 0;//行间距

      public CYTextView(Context context, AttributeSet set)

      {

      super(context,set);

      TypedArray typedArray = context.obtainStyledAttributes(set, R.styleable.CYTextView);

      int width = typedArray.getInt(R.styleable. CY TextView_textwidth, 320);

      float textsize = typedArray.getDimension(R.styleable. CY TextView_textSize, 24);

      int textcolor = typedArray.getColor(R.styleable. CY TextView_textColor, -1442840576);

      float linespace = typedArray.getDimension(R.styleable. CY TextView_lineSpacingExtra, 15);

      int typeface = typedArray.getColor(R.styleable. CY TextView_typeface, 0);

      typedArray.recycle();

      //设置 CY TextView的宽度和行间距www.linuxidc.com

      m_iTextWidth=width;

      LineSpace=linespace;

      // 构建paint对象

      mPaint = new Paint();

      mPaint.setAntiAlias(true);

      mPaint.setColor(textcolor);

      mPaint.setTextSize(textsize);

      switch(typeface){

      case 0:

      mPaint.setTypeface(Typeface.DEFAULT);

      break;

      case 1:

      mPaint.setTypeface(Typeface.SANS_SERIF);

      break;

      case 2:

      mPaint.setTypeface(Typeface.SERIF);

      break;

      case 3:

      mPaint.setTypeface(Typeface.MONOSPACE);

      break;

      default:

      mPaint.setTypeface(Typeface.DEFAULT);

      break;

      }

      }

      @Override

      protected void onDraw(Canvas canvas)

      {

      super.onDraw(canvas);

      char ch;

      int w = 0;

      int istart = 0;

      int m_iFontHeight;

      int m_iRealLine=0;

      int x=2;

      int y=30;

      Vector m_String=new Vector();

      FontMetrics fm = mPaint.getFontMetrics();

      m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + (int)LineSpace;//计算字体高度(字体高度+行间距)

      for (int i = 0; i < string.length(); i++)

      {

      ch = string.charAt(i);

      float[] widths = new float[1];

      String srt = String.valueOf(ch);

      mPaint.getTextWidths(srt, widths);

      if (ch == '/n'){

      m_iRealLine++;

      m_String.addElement(string.substring(istart, i));

      istart = i + 1;

      w = 0;

      }else{

      w += (int) (Math.ceil(widths[0]));

      if (w > m_iTextWidth){

      m_iRealLine++;

      m_String.addElement(string.substring(istart, i));

      istart = i;

      i--;

      w = 0;

      }else{

      if (i == (string.length() - 1)){

      m_iRealLine++;

      m_String.addElement(string.substring(istart, string.length()));

      }

      }

      }

      }

      m_iTextHeight=m_iRealLine*m_iFontHeight+2;

      canvas.setViewport(m_iTextWidth, m_iTextWidth);

      for (int i = 0, j = 0; i < m_iRealLine; i++, j++)

      {

      canvas.drawText((String)(m_String.elementAt(i)), x, y+m_iFontHeight * j, mPaint);

      }

      }

      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

      {

      int measuredHeight = measureHeight(heightMeasureSpec);

      int measuredWidth = measureWidth(widthMeasureSpec);

      this.setMeasuredDimension(measuredWidth, measuredHeight);

      this.setLayoutParams(new LinearLayout.LayoutParams(measuredWidth,measuredHeight));

      super.onMeasure(widthMeasureSpec, heightMeasureSpec);

      }

      private int measureHeight(int measureSpec)

      {

      int specMode = MeasureSpec.getMode(measureSpec);

      int specSize = MeasureSpec.getSize(measureSpec);

      // Default size if no limits are specified.

      initHeight();

      int result = m_iTextHeight;

      if (specMode == MeasureSpec.AT_MOST){

      // Calculate the ideal size of your

      // control within this maximum size.

      // If your control fills the available

      // space return the outer bound.

      result = specSize;

      }else if (specMode == MeasureSpec.EXACTLY){

      // If your control can fit within these bounds return that value.

      result = specSize;

      }

      return result;

      }

      private void initHeight()

      {

      //设置 CY TextView的初始高度为0

      m_iTextHeight=0;

      //大概计算 CY TextView所需高度

      FontMetrics fm = mPaint.getFontMetrics();

      int m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + (int)LineSpace;

      int line=0;

      int istart=0;

      int w=0;

      for (int i = 0; i < string.length(); i++)

      {

      char ch = string.charAt(i);

      float[] widths = new float[1];

      String srt = String.valueOf(ch);

      mPaint.getTextWidths(srt, widths);

      if (ch == '/n'){

      line++;

      istart = i + 1;

      w = 0;

      }else{

      w += (int) (Math.ceil(widths[0]));

      if (w > m_iTextWidth){

      line++;

      istart = i;

      i--;

      w = 0;

      }else{

      if (i == (string.length() - 1)){

      line++;

      }

      }

      }

      }

      m_iTextHeight=(line)*m_iFontHeight+2;

      }

      private int measureWidth(int measureSpec)

      {

      int specMode = MeasureSpec.getMode(measureSpec);

      int specSize = MeasureSpec.getSize(measureSpec);

      // Default size if no limits are specified.

      int result = 500;

      if (specMode == MeasureSpec.AT_MOST){

      // Calculate the ideal size of your control

      // within this maximum size.

      // If your control fills the available space

      // return the outer bound.

      result = specSize;

      }else if (specMode == MeasureSpec.EXACTLY){

      // If your control can fit within these bounds return that value.

      result = specSize;

      }

      return result;

      }

      public void SetText(String text)(注:此函数眼下仅仅有在UI线程中调用才干够把文本画出来,在其他线程中

      无法画文本,找了好久找不到原因,求高手解答)

      {

      string = text;

      // requestLayout();

      // invalidate();

      }

      }

      =======================attrs.xml===============================

      该文件是自己定义的属性,放在project的res/values下

      

      

      

      

      

      

      

      

      

      

      

      

      

      

      

      

      =======================main.xml==========================

      

      <scrollview< p="">

      xmlns:Android="http://schemas.android.com/apk/res/android"

      Android:layout_width="320px"

      Android:layout_height="320px"

      Android:background="#ffffffff"

      >

      <linearlayout< p="">

      xmlns:Android="http://schemas.android.com/apk/res/android"

      Android:orientation="vertical"

      Android:layout_width="fill_parent"

      Android:layout_height="fill_parent">

      <com.cy.cytextview.cytextview< p="">

      xmlns:cy="http://schemas.Android.com/apk/res/ com.cy.CYTextView "

      Android:id="@+id/mv"

      Android:layout_height="wrap_content"

      Android:layout_width="wrap_content"

      cy :textwidth="320"

      cy :textSize="24sp"

      cy :textColor="#aa000000"

      cy :lineSpacingExtra="15sp"

      cy :typeface="serif">

      

      

      

      蓝色代码即为自己定义View,当中以cy命名空间开头的属性是自己定义属性;

      =======================Main.java=============================

      public class Main extends Activity {

      CYTextView mCYTextView;

      String text = "Android提供了静止和有力的组件化模型构建用户的UI部分。主要是基于布局类:View和 ViewGroup。在此基础上,android平台提供了大量的预制的View和xxxViewGroup子 类,即布局(layout)和窗体小部件(widget)。能够用它们构建自己的UI。";

      @Override

      public void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      this.setContentView(R.layout.main);

      mCYTextView = (CYTextView)findViewById(R.id.mv);

      mCYTextView.SetText(text);

      }

      }

     

  • 相关阅读:
    SAP系统和微信集成的系列教程之十:如何在SAP C4C系统里直接回复消息给微信用户
    SAP系统和微信集成的系列教程之九:如何将微信用户发送给微信公众号的内容自动转存到SAP C4C系统
    SAP系统和微信集成的系列教程之八:100行代码在微信公众号里集成地图搜索功能
    漫谈SAP产品里页面上的Checkbox设计与实现系列之一
    一个SAP成都研究院开发工程师的2020年度总结:未知生,焉知死
    Angular form控件原生HTML代码里ng-reflect-form属性和其值的生成时机
    一个SAP成都研究院开发工程师2020年所有文章列表
    SAP系统和微信集成的系列教程之七:使用Redis存储微信用户和公众号的对话记录
    用shell脚本从git上拉取,项目目录下所有各个子项目代码
    shell脚本小计
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4506829.html
Copyright © 2020-2023  润新知