Chinaunix首页 | 论坛 | 博客
  • 博客访问: 465332
  • 博文数量: 145
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1060
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-22 11:52
个人简介

专注计算机技术: Linux Android 云计算 虚拟化 网络

文章分类

全部博文(145)

文章存档

2016年(3)

2015年(21)

2014年(75)

2013年(46)

我的朋友

分类: Android平台

2013-11-13 11:35:02

Android的TextView在显示文字的时候有个问题就是一行还没显示满就跳到下一行,原因是:

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

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

如果只是想让标点符号可以显示在行尾,有一个简单的方法就是在标点符号后加一个空格,则该标点符号就可以显示在行尾了;

如果想要两端对齐的显示效果,有两种方法:

1)修改Android源代码;将frameworks/base/core/java/android/text下的StaticLayout.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.     }

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

2)自定义View显示文本

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

自定义View的步骤:

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

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

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

=========================StartCustomTextView.java=============================


点击(此处)折叠或打开

  1. public class StartCustomTextView 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.     private int left_Margin;
  9.     private int right_Margin;
  10.     private int bottom_Margin;
  11.           
  12.     public StartCustomTextView(Context context, AttributeSet set)
  13.     {
  14.         super(context,set);
  15.         DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
  16.         TypedArray typedArray = context.obtainStyledAttributes(set, R.styleable.CYTextView);
  17.         int width = displayMetrics.widthPixels;
  18.         left_Margin = 29;
  19.         right_Margin = 29;
  20.         bottom_Margin = 29;
  21.         width = width - left_Margin -right_Margin;
  22.         float textsize = typedArray.getDimension(R.styleable.CYTextView_textSize, 34);
  23.         int textcolor = typedArray.getColor(R.styleable.CYTextView_textColor, getResources().getColor(R.color.white));
  24.         float linespace = typedArray.getDimension(R.styleable.CYTextView_lineSpacingExtra, 15);
  25.         int typeface = typedArray.getColor(R.styleable.CYTextView_typeface, 0);
  26.           
  27.         typedArray.recycle();
  28.           
  29.         //设置 CY TextView的宽度和行间距
  30.         m_iTextWidth=width;
  31.         LineSpace=linespace;
  32.           
  33.         // 构建paint对象
  34.         mPaint = new Paint();
  35.         mPaint.setAntiAlias(true);
  36.         mPaint.setColor(textcolor);
  37.         mPaint.setTextSize(textsize);
  38.         switch(typeface){
  39.         case 0:
  40.             mPaint.setTypeface(Typeface.DEFAULT);
  41.             break;
  42.         case 1:
  43.             mPaint.setTypeface(Typeface.SANS_SERIF);
  44.             break;
  45.         case 2:
  46.             mPaint.setTypeface(Typeface.SERIF);
  47.             break;
  48.         case 3:
  49.             mPaint.setTypeface(Typeface.MONOSPACE);
  50.             break;
  51.         default:
  52.             mPaint.setTypeface(Typeface.DEFAULT);
  53.             break;
  54.         }
  55.           
  56.     }
  57.     
  58.     @Override
  59.     protected void onDraw(Canvas canvas)
  60.     {
  61.        super.onDraw(canvas);
  62.           
  63.         char ch;
  64.         int w = 0;
  65.         int istart = 0;
  66.         int m_iFontHeight;
  67.         int m_iRealLine=0;
  68.         int x=2;
  69.         int y=30;
  70.           
  71.         Vector m_String=new Vector();
  72.           
  73.         FontMetrics fm = mPaint.getFontMetrics();
  74.         m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + (int)LineSpace;//计算字体高度(字体高度+行间距)
  75.   
  76.         for (int i = 0; i < string.length(); i++)
  77.         {
  78.             ch = string.charAt(i);
  79.             float[] widths = new float[1];
  80.             String srt = String.valueOf(ch);
  81.             mPaint.getTextWidths(srt, widths);
  82.   
  83.             if (ch == '\n'){
  84.                 m_iRealLine++;
  85.                 m_String.addElement(string.substring(istart, i));
  86.                 istart = i + 1;
  87.                 w = 0;
  88.             }else{
  89.                 w += (int) (Math.ceil(widths[0]));
  90.                 if (w > m_iTextWidth){
  91.                     m_iRealLine++;
  92.                     m_String.addElement(string.substring(istart, i));
  93.                     istart = i;
  94.                     i--;
  95.                     w = 0;
  96.                 }else{
  97.                     if (i == (string.length() - 1)){
  98.                         m_iRealLine++;
  99.                         m_String.addElement(string.substring(istart, string.length()));
  100.                     }
  101.                 }
  102.             }
  103.         }
  104.         m_iTextHeight=m_iRealLine*m_iFontHeight+2;
  105.         canvas.setViewport(m_iTextWidth, m_iTextWidth);
  106.         for (int i = 0, j = 0; i < m_iRealLine; i++, j++)
  107.         {
  108.             canvas.drawText((String)(m_String.elementAt(i)), x, y+m_iFontHeight * j, mPaint);
  109.         }
  110.     }
  111.      
  112.       
  113.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
  114.     {
  115.         int measuredHeight = measureHeight(heightMeasureSpec);
  116.         int measuredWidth = measureWidth(widthMeasureSpec);
  117.         this.setMeasuredDimension(measuredWidth, measuredHeight);
  118.         LayoutParams layout = new LinearLayout.LayoutParams(measuredWidth,measuredHeight);
  119.         layout.leftMargin= left_Margin;
  120.         layout.rightMargin= right_Margin;
  121.         layout.bottomMargin= bottom_Margin;
  122.         this.setLayoutParams(layout);
  123.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  124.     }
  125.                    
  126.     private int measureHeight(int measureSpec)
  127.     {
  128.         int specMode = MeasureSpec.getMode(measureSpec);
  129.         int specSize = MeasureSpec.getSize(measureSpec);
  130.         // Default size if no limits are specified.
  131.         initHeight();
  132.         int result = m_iTextHeight;
  133.         if (specMode == MeasureSpec.AT_MOST){
  134.             // Calculate the ideal size of your
  135.             // control within this maximum size.
  136.             // If your control fills the available
  137.             // space return the outer bound.
  138.             result = specSize;
  139.         }else if (specMode == MeasureSpec.EXACTLY){
  140.             // If your control can fit within these bounds return that value.
  141. // result = specSize;
  142.         }
  143.         return result;
  144.     }
  145.       
  146.     private void initHeight()
  147.     {
  148.         //设置 CY TextView的初始高度为0
  149.         m_iTextHeight=0;
  150.           
  151.         //大概计算 CY TextView所需高度
  152.         FontMetrics fm = mPaint.getFontMetrics();
  153.         int m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + (int)LineSpace;
  154.         int line=0;
  155.         int istart=0;
  156.           
  157.         int w=0;
  158.         for (int i = 0; i < string.length(); i++)
  159.         {
  160.             char ch = string.charAt(i);
  161.             float[] widths = new float[1];
  162.             String srt = String.valueOf(ch);
  163.             mPaint.getTextWidths(srt, widths);
  164.   
  165.             if (ch == '\n'){
  166.                 line++;
  167.                 istart = i + 1;
  168.                 w = 0;
  169.             }else{
  170.                 w += (int) (Math.ceil(widths[0]));
  171.                 if (w > m_iTextWidth){
  172.                     line++;
  173.                     istart = i;
  174.                     i--;
  175.                     w = 0;
  176.                 }else{
  177.                     if (i == (string.length() - 1)){
  178.                         line++;
  179.                     }
  180.                 }
  181.             }
  182.         }
  183.         m_iTextHeight=(line)*m_iFontHeight+2;
  184.     }
  185.                    
  186.     private int measureWidth(int measureSpec)
  187.     {
  188.         int specMode = MeasureSpec.getMode(measureSpec);
  189.         int specSize = MeasureSpec.getSize(measureSpec);
  190.   
  191.         // Default size if no limits are specified.
  192.         int result = 500;
  193.         if (specMode == MeasureSpec.AT_MOST){
  194.             // Calculate the ideal size of your control
  195.             // within this maximum size.
  196.             // If your control fills the available space
  197.             // return the outer bound.
  198.             result = specSize;
  199.         }else if (specMode == MeasureSpec.EXACTLY){
  200.             // If your control can fit within these bounds return that value.
  201.             result = specSize;
  202.         }
  203.         return result;
  204.     }
  205.       
  206.     public void SetText(String text)
  207.     {
  208.         string = text;
  209.        // requestLayout();
  210.       


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

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

点击(此处)折叠或打开

  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==========================

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>
  2.     <ScrollView
  3.     xmlns:Android=""
  4.     Android:layout_width="320px"
  5.     Android:layout_height="320px"
  6.     Android:background="#ffffffff"
  7.     >
  8.     <LinearLayout
  9.     xmlns: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=" 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=============================

点击(此处)折叠或打开

  1. public class Main extends Activity {
  2.     CYTextView mCYTextView;
  3.     String text = "Android 提供了精巧和有力的组件化模型构建用户的UI部分。主要是基于布局类:View和 ViewGroup。在此基础上,android平台提供了大量的预制 的View和xxxViewGroup子 类,即布局(layout)和窗口小部件(widget)。可以用它们构建自己的UI。";
  4.       
  5.     /** Called when the activity is first created. */
  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.     }


点击(此处)折叠或打开

  1. public class Main extends Activity {
  2.     CYTextView mCYTextView;
  3.     String text = "Android 提供了精巧和有力的组件化模型构建用户的UI部分。主要是基于布局类:View和 ViewGroup。在此基础上,android平台提供了大量的预制 的View和xxxViewGroup子 类,即布局(layout)和窗口小部件(widget)。可以用它们构建自己的UI。";
  4.       
  5.     /** Called when the activity is first created. */
  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.     }


点击(此处)折叠或打开

  1. public class Main extends Activity {
  2.     CYTextView mCYTextView;
  3.     String text = "Android 提供了精巧和有力的组件化模型构建用户的UI部分。主要是基于布局类:View和 ViewGroup。在此基础上,android平台提供了大量的预制 的View和xxxViewGroup子 类,即布局(layout)和窗口小部件(widget)。可以用它们构建自己的UI。";
  4.       
  5.     /** Called when the activity is first created. */
  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.     }
  了解更多资讯请关注微信:caaz01


转自:http://hi.baidu.com/java_rose/blog/item/2940a030d1ec7f3e96ddd847.html

阅读(2245) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~