Why does the text layout of Android TextView wrap appear uneven?

Source: Internet
Author: User
Tags getcolor

Why does the text layout of Android TextView wrap appear uneven?

Today, there is no progress in the project, and there is a problem in the background of the company. After reading the notes when I was learning Android, I found that TextView will automatically wrap and the typographical text is uneven. I checked the information and summarized the reasons as follows:

1. Confusion between halfwidth and fullwidth characters: this situation is generally caused by mixing Chinese characters with numbers and English letters

Solution 1:

Returns all characters in textview. Convert all numbers, letters, and punctuation into full-width characters so that they share two bytes with Chinese characters. This can avoid typographical confusion caused by placeholder characters. The code for converting the halfwidth to fullwidth is as follows. You only need to call it.

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 );

}

Solution 2:

Remove special characters or replace all Chinese characters with English letters. Use a regular expression to filter all special characters, or replaceAll () to replace a Chinese character with an English character. After conversion, you can solve the layout confusion problem.

// Replace and filter special characters

Public static String StringFilter (String str) throws PatternSyntaxException {

Str = str. replaceAll ("[", "["). replaceAll ("]", "]"). replaceAll ("! ","! "); // Replace Chinese Characters

String regEx = "[" "]"; // clear special characters

Pattern p = Pattern. compile (regEx );

Matcher m = p. matcher (str );

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

}

2. When TextView displays Chinese characters, punctuation marks cannot be displayed at the beginning and end of a line. If a punctuation mark is at the end of a line, the punctuation marks will be displayed in the next line together with the previous character.

Solution: Add a space after the punctuation mark.

3. An English word cannot be displayed in two rows (when TextView is displayed in English, punctuation marks can be placed at the end of a line, but English words cannot be separated ).

4. If you want two rows to show the effect: There are two methods:

Method 1:

Modify the Android source code. Set the following code in the StaticLayout. java file in frameworks/base/core/java/android/text:

If (c = ''| c = '/T' |

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

(J-1

(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;

}

Remove it. After removal, punctuation marks can be displayed at the beginning and end of a line, and English words can also be displayed separately in two lines.

Method 2:

Custom View display text

On the Internet, some experts used custom views to solve this problem. I did an experiment and summarized it:

To customize a View, follow these steps:

1) inherit the View class or its subclass. The example inherits the TextView class;

2) write the constructor and get the attributes through XML (you can customize the attributes in this step, see the routine );

3) rewrite some functions of the parent class, which generally start with on. In this example, the onDraw () and onMeasure () functions are rewritten;

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

Public class CYTextView extends TextView {

Public static int m_iTextHeight; // text height

Public static int m_iTextWidth; // text width

Private Paint mPaint = null;

Private String string = "";

Private float LineSpace = 0; // line spacing

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 ();

// Set CY TextView width and line spacing www.linuxidc.com

M_iTextWidth = width;

LineSpace = linespace;

// Construct the paint object

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; // calculate the font height (font height + row spacing)

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 ()

{

// Set the initial height of CY TextView to 0

M_iTextHeight = 0;

// Calculate the height required by 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) (Note: Currently, this function can be used only in the UI thread to draw the text. In other threads

Unable to draw text. I have been searching for a long time and cannot find the reason. Could you please help me)

{

String = text;

// RequestLayout ();

// Invalidate ();

}

}

===================================== Attrs. xml ====================================

This file is a custom property and is placed under res/values of the project.

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

===================================== Main. xml =

  

  

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

Android: layout_width = "320px"

Android: layout_height = "320px"

Android: background = "# ffffffff"

>

  

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

Android: orientation = "vertical"

Android: layout_width = "fill_parent"

Android: layout_height = "fill_parent">

  

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

  

  

  

The blue code is a custom View. The property starting with cy namespace is a custom property;

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

Public class Main extends Activity {

CYTextView mCYTextView;

String text = "Android provides a sophisticated and powerful componentized model to build the UI of a user. Mainly based on the layout class: View and ViewGroup. On this basis, the android platform provides a large number of pre-fabricated views and xxxViewGroup sub-classes, that is, layout and widgets ). You can use them to build your own UI. ";

@ Override

Public void onCreate (Bundle savedInstanceState ){

Super. onCreate (savedInstanceState );

This. setContentView (R. layout. main );

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

MCYTextView. SetText (text );

}

}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.