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


    转载:http://niufc.iteye.com/blog/1729792

    发现TextView会自动换行,而且排版文字参差不齐。查了下资料,总结原因如下:

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

    解决方法一:

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

     

    Java代码  收藏代码
    1. public static String ToDBC(String input) {  
    2.    char[] c = input.toCharArray();  
    3.    for (int i = 0; i< c.length; i++) {  
    4.        if (c[i] == 12288) {  
    5.          c[i] = (char32;  
    6.          continue;  
    7.        }if (c[i]> 65280&& c[i]< 65375)  
    8.           c[i] = (char) (c[i] - 65248);  
    9.        }  
    10.    return new String(c);  
    11. }  

    解决方法二:

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

    Java代码  收藏代码
    1. // 替换、过滤特殊字符  
    2. public static String StringFilter(String str) throws PatternSyntaxException{  
    3.     str=str.replaceAll("【","[").replaceAll("】","]").replaceAll("!","!");//替换中文标号  
    4.     String regEx="[『』]"// 清除掉特殊字符  
    5.     Pattern p = Pattern.compile(regEx);  
    6.     Matcher m = p.matcher(str);  
    7.  return m.replaceAll("").trim();  
    8. }  

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

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

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

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

    方法一:

    修改Android源代码;将frameworks/base/core/java/android/text下的StaticLayout.java文件中的如下代码:

    Java代码  收藏代码
    1. if (c == ' ' || c == '/t' ||  
    2.                           ((c == '.'  || c == ',' || c == ':' || c == ';') &&  
    3.                            (j - 1 < here || !Character.isDigit(chs[j - 1 - start])) &&  
    4.                            (j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||  
    5.                           ((c == '/' || c == '-') &&  
    6.                            (j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||  
    7.                           (c >= FIRST_CJK && isIdeographic(c, true) &&  
    8.                            j + 1 < next && isIdeographic(chs[j + 1 - start], false))) {  
    9.                           okwidth = w;  
    10.                           ok = j + 1;  
    11.   
    12.                           if (fittop < oktop)  
    13.                               oktop = fittop;  
    14.                           if (fitascent < okascent)  
    15.                               okascent = fitascent;  
    16.                           if (fitdescent > okdescent)  
    17.                               okdescent = fitdescent;  
    18.                           if (fitbottom > okbottom)  
    19.                               okbottom = fitbottom;  
    20.                       }  

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

    方法二:

    自定义View显示文本

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

    自定义View的步骤: 

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

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

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

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

    Java代码  收藏代码
    1. public class CYTextView extends TextView {  
    2.     public  static  int m_iTextHeight; //文本的高度  
    3.     public  static  int m_iTextWidth;//文本的宽度  
    4.      
    5.     private Paint mPaint = null;  
    6.     private String string="";  
    7.     private float LineSpace = 0;//行间距  
    8.          
    9.     public CYTextView(Context context, AttributeSet set)  
    10.     {        
    11.         super(context,set);   
    12.   
    13.         TypedArray typedArray = context.obtainStyledAttributes(set, R.styleable.CYTextView);  
    14.   
    15.         int width = typedArray.getInt(R.styleable. CY TextView_textwidth, 320);  
    16.         float textsize = typedArray.getDimension(R.styleable. CY TextView_textSize, 24);  
    17.         int textcolor = typedArray.getColor(R.styleable. CY TextView_textColor, -1442840576);  
    18.         float linespace = typedArray.getDimension(R.styleable. CY TextView_lineSpacingExtra, 15);  
    19.         int typeface = typedArray.getColor(R.styleable. CY TextView_typeface, 0);  
    20.          
    21.         typedArray.recycle();  
    22.          
    23.         //设置 CY TextView的宽度和行间距www.linuxidc.com  
    24.         m_iTextWidth=width;  
    25.         LineSpace=linespace;  
    26.          
    27.         // 构建paint对象       
    28.         mPaint = new Paint();  
    29.         mPaint.setAntiAlias(true);  
    30.         mPaint.setColor(textcolor);  
    31.         mPaint.setTextSize(textsize);  
    32.         switch(typeface){  
    33.         case 0:  
    34.             mPaint.setTypeface(Typeface.DEFAULT);  
    35.             break;  
    36.         case 1:  
    37.             mPaint.setTypeface(Typeface.SANS_SERIF);  
    38.             break;  
    39.         case 2:  
    40.             mPaint.setTypeface(Typeface.SERIF);  
    41.             break;  
    42.         case 3:  
    43.             mPaint.setTypeface(Typeface.MONOSPACE);  
    44.             break;  
    45.         default:  
    46.             mPaint.setTypeface(Typeface.DEFAULT);     
    47.             break;  
    48.         }  
    49.          
    50.     }  
    51.    
    52.     @Override  
    53.     protected void onDraw(Canvas canvas)  
    54.     {   
    55.        super.onDraw(canvas);        
    56.          
    57.         char ch;  
    58.         int w = 0;  
    59.         int istart = 0;  
    60.         int m_iFontHeight;  
    61.         int m_iRealLine=0;  
    62.         int x=2;  
    63.         int y=30;  
    64.          
    65.         Vector    m_String=new Vector();  
    66.          
    67.         FontMetrics fm = mPaint.getFontMetrics();         
    68.         m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + (int)LineSpace;//计算字体高度(字体高度+行间距)  
    69.   
    70.         for (int i = 0; i < string.length(); i++)  
    71.         {  
    72.             ch = string.charAt(i);  
    73.             float[] widths = new float[1];  
    74.             String srt = String.valueOf(ch);  
    75.             mPaint.getTextWidths(srt, widths);  
    76.   
    77.             if (ch == '/n'){  
    78.                 m_iRealLine++;  
    79.                 m_String.addElement(string.substring(istart, i));  
    80.                 istart = i + 1;  
    81.                 w = 0;  
    82.             }else{  
    83.                 w += (int) (Math.ceil(widths[0]));  
    84.                 if (w > m_iTextWidth){  
    85.                     m_iRealLine++;  
    86.                     m_String.addElement(string.substring(istart, i));  
    87.                     istart = i;  
    88.                     i--;  
    89.                     w = 0;  
    90.                 }else{  
    91.                     if (i == (string.length() - 1)){  
    92.                         m_iRealLine++;  
    93.                         m_String.addElement(string.substring(istart, string.length()));  
    94.                     }  
    95.                 }  
    96.             }  
    97.         }  
    98.         m_iTextHeight=m_iRealLine*m_iFontHeight+2;  
    99.         canvas.setViewport(m_iTextWidth, m_iTextWidth);  
    100.         for (int i = 0, j = 0; i < m_iRealLine; i++, j++)  
    101.         {  
    102.             canvas.drawText((String)(m_String.elementAt(i)), x,  y+m_iFontHeight * j, mPaint);  
    103.         }  
    104.     }   
    105.     
    106.      
    107.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
    108.     {           
    109.         int measuredHeight = measureHeight(heightMeasureSpec);           
    110.         int measuredWidth = measureWidth(widthMeasureSpec);            
    111.         this.setMeasuredDimension(measuredWidth, measuredHeight);  
    112.         this.setLayoutParams(new LinearLayout.LayoutParams(measuredWidth,measuredHeight));  
    113.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
    114.     }   
    115.                   
    116.     private int measureHeight(int measureSpec)  
    117.     {   
    118.         int specMode = MeasureSpec.getMode(measureSpec);           
    119.         int specSize = MeasureSpec.getSize(measureSpec);                    
    120.         // Default size if no limits are specified.   
    121.         initHeight();  
    122.         int result = m_iTextHeight;           
    123.         if (specMode == MeasureSpec.AT_MOST){          
    124.             // Calculate the ideal size of your           
    125.             // control within this maximum size.           
    126.             // If your control fills the available            
    127.             // space return the outer bound.           
    128.             result = specSize;            
    129.         }else if (specMode == MeasureSpec.EXACTLY){            
    130.             // If your control can fit within these bounds return that value.             
    131.             result = specSize;            
    132.         }            
    133.         return result;             
    134.     }   
    135.      
    136.     private void initHeight()  
    137.     {  
    138.         //设置 CY TextView的初始高度为0  
    139.         m_iTextHeight=0;  
    140.          
    141.         //大概计算 CY TextView所需高度  
    142.         FontMetrics fm = mPaint.getFontMetrics();         
    143.         int m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + (int)LineSpace;  
    144.         int line=0;  
    145.         int istart=0;  
    146.          
    147.         int w=0;  
    148.         for (int i = 0; i < string.length(); i++)  
    149.         {  
    150.             char ch = string.charAt(i);  
    151.             float[] widths = new float[1];  
    152.             String srt = String.valueOf(ch);  
    153.             mPaint.getTextWidths(srt, widths);  
    154.   
    155.             if (ch == '/n'){  
    156.                 line++;  
    157.                 istart = i + 1;  
    158.                 w = 0;  
    159.             }else{  
    160.                 w += (int) (Math.ceil(widths[0]));  
    161.                 if (w > m_iTextWidth){  
    162.                     line++;  
    163.                     istart = i;  
    164.                     i--;  
    165.                     w = 0;  
    166.                 }else{  
    167.                     if (i == (string.length() - 1)){  
    168.                         line++;  
    169.                     }  
    170.                 }  
    171.             }  
    172.         }  
    173.         m_iTextHeight=(line)*m_iFontHeight+2;  
    174.     }  
    175.                   
    176.     private int measureWidth(int measureSpec)  
    177.     {   
    178.         int specMode = MeasureSpec.getMode(measureSpec);            
    179.         int specSize = MeasureSpec.getSize(measureSpec);              
    180.            
    181.         // Default size if no limits are specified.           
    182.         int result = 500;           
    183.         if (specMode == MeasureSpec.AT_MOST){           
    184.             // Calculate the ideal size of your control            
    185.             // within this maximum size.          
    186.             // If your control fills the available space          
    187.             // return the outer bound.          
    188.             result = specSize;           
    189.         }else if (specMode == MeasureSpec.EXACTLY){            
    190.             // If your control can fit within these bounds return that value.            
    191.             result = specSize;             
    192.         }            
    193.         return result;           
    194.     }  
    195. public void SetText(String text)(//注:此函数目前只有在UI线程中调用才可以把文本画出来,在其它线程中<p>                                                        //无法画文本,找了好久找不到原因,求高手解答)  
    196.     {  
    197.         string = text;  
    198.        // requestLayout();  
    199.        // invalidate();  
    200.     }    
    201. }</p>  

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

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

    Java代码  收藏代码
    1. <resources>  
    2.     <attr name="textwidth" format="integer"/>  
    3.     <attr name="typeface">  
    4.         <enum name="normal" value="0"/>  
    5.         <enum name="sans" value="1"/>  
    6.         <enum name="serif" value="2"/>  
    7.         <enum name="monospace" value="3"/>  
    8.     </attr>  
    9.   
    10.     <declare-styleable name="CYTextView">     
    11.         <attr name="textwidth" />         
    12.         <attr name="textSize" format="dimension"/>  
    13.         <attr name="textColor" format="reference|color"/>  
    14.         <attr name="lineSpacingExtra" format="dimension"/>  
    15.         <attr name="typeface" />  
    16.         </declare-styleable>  
    17. </resources>  

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

    Java代码  收藏代码
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <ScrollView  
    3.         xmlns:Android="http://schemas.android.com/apk/res/android"  
    4.         Android:layout_width="320px"  
    5.         Android:layout_height="320px"  
    6.         Android:background="#ffffffff"  
    7.         >  
    8.   <LinearLayout  
    9.         xmlns:Android="http://schemas.android.com/apk/res/android"  
    10.         Android:orientation="vertical"  
    11.         Android:layout_width="fill_parent"  
    12.         Android:layout_height="fill_parent">  
    13.     <com.cy.CYTextView.CYTextView  
    14.         xmlns:cy="http://schemas.Android.com/apk/res/ com.cy.CYTextView "  
    15.         Android:id="@+id/mv"  
    16.         Android:layout_height="wrap_content"  
    17.         Android:layout_width="wrap_content"  
    18.         cy :textwidth="320"         
    19.         cy :textSize="24sp"  
    20.         cy :textColor="#aa000000"  
    21.         cy :lineSpacingExtra="15sp"  
    22.         cy :typeface="serif">  
    23.     </com. cy .CYTextView.CYTextView>     
    24.   </LinearLayout>  
    25. </ScrollView>  

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

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

    Java代码  收藏代码
    1. public class Main extends Activity {  
    2.     CYTextView mCYTextView;  
    3.     String text = "Android 提供了精巧和有力的组件化模型构建用户的UI部分。主要是基于布局类:View和        ViewGroup。在此基础上,android平台提 供了大量的预制的View和xxxViewGroup子类,即布局(layout)和窗口小部件(widget)。可以用它们构建自己的UI。";  
    4.      
    5.      
    6.     @Override  
    7.     public void onCreate(Bundle savedInstanceState) {  
    8.         super.onCreate(savedInstanceState);  
    9.         this.setContentView(R.layout.main);  
    10.          
    11.         mCYTextView = (CYTextView)findViewById(R.id.mv);  
    12.         mCYTextView.SetText(text);  
    13.     }  
    14.   
    15. }  
  • 相关阅读:
    protobuf 使用
    rsync实现Linux与windows增量更新数据
    单例模式-通用写法1
    cxf RESTful service client
    IDEAspringboot项目自动生成junit测试
    Centos8配置网络NM
    Oracle终止正在执行中的存储过程
    Mysql Statement violates GTID consistency: CREATE TABLE ... SELECT.
    shell中判断变量是否存在某个集合中
    redis-ha部署
  • 原文地址:https://www.cnblogs.com/qhyhao/p/3706856.html
Copyright © 2020-2023  润新知