android textview automatic line break neat typesetting

Keywords: Android xml Java

Code that you have been searching for for a long time on the Internet has been found. After testing, it can be used. Write it down first for later use.Diagram of the effect of the previous experiment


There are two textview s on the diagram. See below for the differences.


The following is the original copy:

1. Where are the problems?

textview will automatically wrap when long text is displayed. In some special cases, the automatic wrap will look like this:


These special cases include:

1) Full-angle/half-angle symbols (typically numbers, letters, Chinese characters)

2) When a full/half punctuation symbol appears at the beginning of a line, it jumps to the next line along with the previous character

3) English words cannot be broken into two lines

4)......

2. What to do?

There are usually two types of solutions:

1) Modify the text content, make all symbols full-angled, add spaces before punctuation symbols, and so on...

2) Keep the contents of the text unchanged and manually divide the text into multiple lines where appropriate

This paper uses the second scheme, which is more general and preserves the original text to the maximum extent.

3. Start working

3.1 "Manually dividing text into multiple lines where appropriate" requires information such as the actual width and font size of the textview, as follows:

  1. public class TestCActivity extends Activity {  
  2.     private TextView mText;  
  3.       
  4.     @Override  
  5.     protected void onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.           
  8.         setContentView(R.layout.testc);  
  9.           
  10.         mText = (TextView)findViewById(R.id.txt);  
  11.         mText.setText("This article address http://Www.cnblogs.com/goagent/p/5159125.html This is the address of this article.Address.Ah http://www.cnblogs.com/goagent/p/5159125.html");  
  12.         mText.getViewTreeObserver().addOnGlobalLayoutListener(new OnTvGlobalLayoutListener());  
  13.     }  
  14.   
  15.     private class OnTvGlobalLayoutListener implements OnGlobalLayoutListener {  
  16.         @Override  
  17.         public void onGlobalLayout() {  
  18.             mText.getViewTreeObserver().removeOnGlobalLayoutListener(this);  
  19.             final String newText = autoSplitText(mText);  
  20.             if (!TextUtils.isEmpty(newText)) {  
  21.                 mText.setText(newText);  
  22.             }  
  23.         }  
  24.     }  
  25.       
  26.     private String autoSplitText(final TextView tv) {  
  27.         final String rawText = tv.getText().toString();  
  28.         final Paint tvPaint = tv.getPaint();  
  29.         final int tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight();  
  30.           
  31.         //autoSplitText begin....  
  32.         String newText = rawText;  
  33.         //autoSplitText end....  
  34.           
  35.         return newText;  
  36.     }  
  37. }  
3.2 To automatically split text, simply measure it character by character with paint of textview. If you find that the current line cannot be drawn anymore, add a line break manually:
  1. private String autoSplitText(final TextView tv) {  
  2.         final String rawText = tv.getText().toString(); //Original Text  
  3.         final Paint tvPaint = tv.getPaint(); //paint, contains information such as fonts  
  4.         final float tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); //Control Available Width  
  5.           
  6.         //Split the original text by line  
  7.         String [] rawTextLines = rawText.replaceAll("\r""").split("\n");  
  8.         StringBuilder sbNewText = new StringBuilder();  
  9.         for (String rawTextLine : rawTextLines) {  
  10.             if (tvPaint.measureText(rawTextLine) <= tvWidth) {  
  11.                 //If the full line width is within the available width of the control, it is not handled  
  12.                 sbNewText.append(rawTextLine);  
  13.             } else {  
  14.                 //If the full line width exceeds the available width of the control, it is measured by character and wrapped manually at the first character that exceeds the available width  
  15.                 float lineWidth = 0;  
  16.                 for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) {  
  17.                     char ch = rawTextLine.charAt(cnt);  
  18.                     lineWidth += tvPaint.measureText(String.valueOf(ch));  
  19.                     if (lineWidth <= tvWidth) {  
  20.                         sbNewText.append(ch);  
  21.                     } else {  
  22.                         sbNewText.append("\n");  
  23.                         lineWidth = 0;  
  24.                         --cnt;  
  25.                     }  
  26.                 }  
  27.             }  
  28.             sbNewText.append("\n");  
  29.         }  
  30.           
  31.         //Remove the extra\n at the end  
  32.         if (!rawText.endsWith("\n")) {  
  33.             sbNewText.deleteCharAt(sbNewText.length() - 1);  
  34.         }  
  35.           
  36.         return sbNewText.toString();  
  37.     }  

3.3. Say nothing but the following:


4. More Plays

4.1. You can encapsulate a custom textview that directly includes the ability to automatically type and wrap lines:

  1. package cc.snser.test;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Paint;  
  5. import android.text.TextUtils;  
  6. import android.util.AttributeSet;  
  7. import android.widget.TextView;  
  8.   
  9. public class AutoSplitTextView extends TextView {  
  10.     private boolean mEnabled = true;  
  11.   
  12.     public AutoSplitTextView(Context context) {  
  13.         super(context);  
  14.     }  
  15.   
  16.     public AutoSplitTextView(Context context, AttributeSet attrs) {  
  17.         super(context, attrs);  
  18.     }  
  19.   
  20.     public AutoSplitTextView(Context context, AttributeSet attrs, int defStyle) {  
  21.         super(context, attrs, defStyle);  
  22.     }  
  23.       
  24.     public void setAutoSplitEnabled(boolean enabled) {  
  25.         mEnabled = enabled;  
  26.     }  
  27.       
  28.     @Override  
  29.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  30.         if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY   
  31.             && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY  
  32.             && getWidth() > 0   
  33.             && getHeight() > 0  
  34.             && mEnabled) {  
  35.             String newText = autoSplitText(this);  
  36.             if (!TextUtils.isEmpty(newText)) {  
  37.                 setText(newText);  
  38.             }  
  39.         }  
  40.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  41.     }  
  42.       
  43.     private String autoSplitText(final TextView tv) {  
  44.         final String rawText = tv.getText().toString(); //Original Text  
  45.         final Paint tvPaint = tv.getPaint(); //paint, contains information such as fonts  
  46.         final float tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); //Control Available Width  
  47.           
  48.         //Split the original text by line  
  49.         String [] rawTextLines = rawText.replaceAll("\r""").split("\n");  
  50.         StringBuilder sbNewText = new StringBuilder();  
  51.         for (String rawTextLine : rawTextLines) {  
  52.             if (tvPaint.measureText(rawTextLine) <= tvWidth) {  
  53.                 //If the full line width is within the available width of the control, it is not handled  
  54.                 sbNewText.append(rawTextLine);  
  55.             } else {  
  56.                 //If the full line width exceeds the available width of the control, it is measured by character and wrapped manually at the first character that exceeds the available width  
  57.                 float lineWidth = 0;  
  58.                 for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) {  
  59.                     char ch = rawTextLine.charAt(cnt);  
  60.                     lineWidth += tvPaint.measureText(String.valueOf(ch));  
  61.                     if (lineWidth <= tvWidth) {  
  62.                         sbNewText.append(ch);  
  63.                     } else {  
  64.                         sbNewText.append("\n");  
  65.                         lineWidth = 0;  
  66.                         --cnt;  
  67.                     }  
  68.                 }  
  69.             }  
  70.             sbNewText.append("\n");  
  71.         }  
  72.           
  73.         //Remove the extra\n at the end  
  74.         if (!rawText.endsWith("\n")) {  
  75.             sbNewText.deleteCharAt(sbNewText.length() - 1);  
  76.         }  
  77.           
  78.         return sbNewText.toString();  
  79.     }  
  80. }  
  81.   
  82. View AutoSplitTextView.java  

TestActivity code:

  1. package cc.snser.test;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5.   
  6. public class TestCActivity extends Activity {  
  7.     private AutoSplitTextView mText;  
  8.       
  9.     @Override  
  10.     protected void onCreate(Bundle savedInstanceState) {  
  11.         super.onCreate(savedInstanceState);  
  12.           
  13.         setContentView(R.layout.testc);  
  14.           
  15.         mText = (AutoSplitTextView)findViewById(R.id.txt);  
  16.         mText.setText("This article address http://Www.cnblogs.com/goagent/p/5159125.html This is the address of this article.Address.Ah http://www.cnblogs.com/goagent/p/5159125.html;)
  17.     }  
  18. }  

xml code:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="@android:color/white"  
  6.     android:orientation="vertical" >  
  7.   
  8.     <cc.snser.test.AutoSplitTextView  
  9.         android:id="@+id/txt"  
  10.         android:layout_width="match_parent"  
  11.         android:layout_height="200dp"  
  12.         android:layout_marginTop="11dp"  
  13.         android:layout_marginLeft="11dp"  
  14.         android:layout_marginRight="11dp"  
  15.         android:background="@android:color/holo_blue_light"  
  16.         android:textSize="20sp"  
  17.         android:textColor="@android:color/black" />  
  18.       
  19. </LinearLayout>  

4.2. Hanging indentation

  1. private String autoSplitText(final TextView tv, final String indent) {  
  2.         final String rawText = tv.getText().toString(); //Original Text
  3.         final Paint tvPaint = tv.getPaint(); //paint, containing information such as fonts
  4.         final float tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); //Control Available Width
  5.           
  6.         //Process indentation into spaces
  7.         String indentSpace = "";  
  8.         float indentWidth = 0;  
  9.         if (!TextUtils.isEmpty(indent)) {  
  10.             float rawIndentWidth = tvPaint.measureText(indent);  
  11.             if (rawIndentWidth < tvWidth) {  
  12.                 while ((indentWidth = tvPaint.measureText(indentSpace)) < rawIndentWidth) {  
  13.                     indentSpace += " ";  
  14.                 }  
  15.             }  
  16.         }  
  17.           
  18.         //Split the original text by line
  19.         String [] rawTextLines = rawText.replaceAll("\r", "").split("\n");  
  20.         StringBuilder sbNewText = new StringBuilder();  
  21.         for (String rawTextLine : rawTextLines) {  
  22.             if (tvPaint.measureText(rawTextLine) <= tvWidth) {  
  23.                 //If the full line width is within the available width of the control, it is not handled.
  24.                 sbNewText.append(rawTextLine);  
  25.             } else {  
  26.                 //If the full line width exceeds the available width of the control, it is measured by character and wrapped manually at the first character that exceeds the available width.
  27.                 float lineWidth = 0;  
  28.                 for (int cnt = 0; cnt != rawTextLine.length(); ++cnt) {  
  29.                     char ch = rawTextLine.charAt(cnt);  
  30.                     //Start with the second line of the manual line break with hanging indentation
  31.                     if (lineWidth < 0.1f && cnt != 0) {  
  32.                         sbNewText.append(indentSpace);  
  33.                         lineWidth += indentWidth;  
  34.                     }  
  35.                     lineWidth += tvPaint.measureText(String.valueOf(ch));  
  36.                     if (lineWidth <= tvWidth) {  
  37.                         sbNewText.append(ch);  
  38.                     } else {  
  39.                         sbNewText.append("\n");  
  40.                         lineWidth = 0;  
  41.                         --cnt;  
  42.                     }  
  43.                 }  
  44.             }  
  45.             sbNewText.append("\n");  
  46.         }  
  47.           
  48.         //Remove \n from the end
  49.         if (!rawText.endsWith("\n")) {  
  50.             sbNewText.deleteCharAt(sbNewText.length() - 1);  
  51.         }  
  52.           
  53.         return sbNewText.toString();  
  54.     }  

Call method:

 autoSplitText(tv, "1,"); 

Hanging indentation effect:


Note: You need to use AutoSplitTextView in the xml of the layout instead of the native TextView, otherwise it will be the same as the effect image at the beginning of the article.

Posted by joon on Mon, 01 Jul 2019 09:38:57 -0700