对于字符串处理Android为我们提供了一个简单实用的TextUtils类,如果处理比较简单的内容不用去思考正则表达式不妨试试这个在android.text.TextUtils的类,主要的功能如下:


  1.  //是否为空字符
  2.  Log.e("textUtils+isEmpty", "******" + TextUtils.isEmpty("12344556"));  
  3.  Log.e("textUtils+isEmpty", "******" + TextUtils.isEmpty(""));  (此处注意:空格返回false

  4.  //判断是否只含有数字  
  5.  Log.e("textUtils+isDigitsOnly", TextUtils.isDigitsOnly("123432")  
  6.          + "***" + TextUtils.isDigitsOnly("sssssss")  
  7.          + "***" + TextUtils.isDigitsOnly("123ssss"));  

  8.  //判断是否含有可打印字符  
  9.  Log.e("textUtils+isGraphic", TextUtils.isGraphic('2')  
  10.          + "***" + TextUtils.isGraphic("s32414314"));  

  11.  //翻转指定的字符串  
  12.  Log.e("textUtils+getReverse", TextUtils.getReverse("hello", 1, 5) + "");  

  13.  //拼接字符串  
  14.  Log.e("textUtils+concat", TextUtils.concat("one", " ", "two!").toString());  

  15.  //判断字符串是否相等  
  16.  Log.e("textUtils+equals", TextUtils.equals("equal", "equal")  
  17.          + "***" + TextUtils.equals("hello", "Hello")  
  18.          + "***" + TextUtils.equals("one1", "equal"));  

  19.  //判断字符串长度,首位去空字符  
  20.  Log.e("textUtils+getTrimmedLength", TextUtils.getTrimmedLength("length")  
  21.          + "***" + TextUtils.getTrimmedLength("  leng th")); 
  22.  
  23.  //判断子字符串第一次出现的位置 返回位置数  
  24.  Log.e("textUtils+indexOf", TextUtils.indexOf("hello android ,you are so wonderful!", "android") + "");  
  25.  //截取字符串  
  26.  Log.e("textUtils+substring", TextUtils.substring("Hello android!", 0, 5));  

  27.  //分割字符串并获取分割后指定位置的子字符串  
  28.  Log.e("textUtils+split", TextUtils.split(" Hello android!", "e")[0]  
  29.          + "***" + TextUtils.split(" Hello android!", "e")[1]);  

  30. // 在数组中每个元素之间使用“-”来连接
  31.   Log.e("textUtils+split", TextUtils.join("-", list));

  32. // 使用html编码字符串
  33. Log.e("textUtils+split", TextUtils.htmlEncode(f) + "");


附上TextUtils源码供大家自行探索:

[java]  view plain  copy
  1. /* 
  2.  * Copyright (C) 2006 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. package android.text;  
  18.   
  19. import android.content.res.Resources;  
  20. import android.os.Parcel;  
  21. import android.os.Parcelable;  
  22. import android.text.style.AbsoluteSizeSpan;  
  23. import android.text.style.AlignmentSpan;  
  24. import android.text.style.BackgroundColorSpan;  
  25. import android.text.style.BulletSpan;  
  26. import android.text.style.CharacterStyle;  
  27. import android.text.style.EasyEditSpan;  
  28. import android.text.style.ForegroundColorSpan;  
  29. import android.text.style.LeadingMarginSpan;  
  30. import android.text.style.LocaleSpan;  
  31. import android.text.style.MetricAffectingSpan;  
  32. import android.text.style.QuoteSpan;  
  33. import android.text.style.RelativeSizeSpan;  
  34. import android.text.style.ReplacementSpan;  
  35. import android.text.style.ScaleXSpan;  
  36. import android.text.style.SpellCheckSpan;  
  37. import android.text.style.StrikethroughSpan;  
  38. import android.text.style.StyleSpan;  
  39. import android.text.style.SubscriptSpan;  
  40. import android.text.style.SuggestionRangeSpan;  
  41. import android.text.style.SuggestionSpan;  
  42. import android.text.style.SuperscriptSpan;  
  43. import android.text.style.TextAppearanceSpan;  
  44. import android.text.style.TypefaceSpan;  
  45. import android.text.style.URLSpan;  
  46. import android.text.style.UnderlineSpan;  
  47. import android.util.Log;  
  48. import android.util.Printer;  
  49.   
  50. import android.view.View;  
  51. import com.android.internal.R;  
  52. import com.android.internal.util.ArrayUtils;  
  53. import libcore.icu.ICU;  
  54.   
  55. import java.lang.reflect.Array;  
  56. import java.util.Iterator;  
  57. import java.util.Locale;  
  58. import java.util.regex.Pattern;  
  59.   
  60. public class TextUtils {  
  61.     private static final String TAG = "TextUtils";  
  62.   
  63.   
  64.     private TextUtils() { /* cannot be instantiated */ }  
  65.   
  66.     public static void getChars(CharSequence s, int start, int end,  
  67.                                 char[] dest, int destoff) {  
  68.         Class<? extends CharSequence> c = s.getClass();  
  69.   
  70.         if (c == String.class)  
  71.             ((String) s).getChars(start, end, dest, destoff);  
  72.         else if (c == StringBuffer.class)  
  73.             ((StringBuffer) s).getChars(start, end, dest, destoff);  
  74.         else if (c == StringBuilder.class)  
  75.             ((StringBuilder) s).getChars(start, end, dest, destoff);  
  76.         else if (s instanceof GetChars)  
  77.             ((GetChars) s).getChars(start, end, dest, destoff);  
  78.         else {  
  79.             for (int i = start; i < end; i++)  
  80.                 dest[destoff++] = s.charAt(i);  
  81.         }  
  82.     }  
  83.   
  84.     public static int indexOf(CharSequence s, char ch) {  
  85.         return indexOf(s, ch, 0);  
  86.     }  
  87.   
  88.     public static int indexOf(CharSequence s, char ch, int start) {  
  89.         Class<? extends CharSequence> c = s.getClass();  
  90.   
  91.         if (c == String.class)  
  92.             return ((String) s).indexOf(ch, start);  
  93.   
  94.         return indexOf(s, ch, start, s.length());  
  95.     }  
  96.   
  97.     public static int indexOf(CharSequence s, char ch, int start, int end) {  
  98.         Class<? extends CharSequence> c = s.getClass();  
  99.   
  100.         if (s instanceof GetChars || c == StringBuffer.class ||  
  101.             c == StringBuilder.class || c == String.class) {  
  102.             final int INDEX_INCREMENT = 500;  
  103.             char[] temp = obtain(INDEX_INCREMENT);  
  104.   
  105.             while (start < end) {  
  106.                 int segend = start + INDEX_INCREMENT;  
  107.                 if (segend > end)  
  108.                     segend = end;  
  109.   
  110.                 getChars(s, start, segend, temp, 0);  
  111.   
  112.                 int count = segend - start;  
  113.                 for (int i = 0; i < count; i++) {  
  114.                     if (temp[i] == ch) {  
  115.                         recycle(temp);  
  116.                         return i + start;  
  117.                     }  
  118.                 }  
  119.   
  120.                 start = segend;  
  121.             }  
  122.   
  123.             recycle(temp);  
  124.             return -1;  
  125.         }  
  126.   
  127.         for (int i = start; i < end; i++)  
  128.             if (s.charAt(i) == ch)  
  129.                 return i;  
  130.   
  131.         return -1;  
  132.     }  
  133.   
  134.     public static int lastIndexOf(CharSequence s, char ch) {  
  135.         return lastIndexOf(s, ch, s.length() - 1);  
  136.     }  
  137.   
  138.     public static int lastIndexOf(CharSequence s, char ch, int last) {  
  139.         Class<? extends CharSequence> c = s.getClass();  
  140.   
  141.         if (c == String.class)  
  142.             return ((String) s).lastIndexOf(ch, last);  
  143.   
  144.         return lastIndexOf(s, ch, 0, last);  
  145.     }  
  146.   
  147.     public static int lastIndexOf(CharSequence s, char ch,  
  148.                                   int start, int last) {  
  149.         if (last < 0)  
  150.             return -1;  
  151.         if (last >= s.length())  
  152.             last = s.length() - 1;  
  153.   
  154.         int end = last + 1;  
  155.   
  156.         Class<? extends CharSequence> c = s.getClass();  
  157.   
  158.         if (s instanceof GetChars || c == StringBuffer.class ||  
  159.             c == StringBuilder.class || c == String.class) {  
  160.             final int INDEX_INCREMENT = 500;  
  161.             char[] temp = obtain(INDEX_INCREMENT);  
  162.   
  163.             while (start < end) {  
  164.                 int segstart = end - INDEX_INCREMENT;  
  165.                 if (segstart < start)  
  166.                     segstart = start;  
  167.   
  168.                 getChars(s, segstart, end, temp, 0);  
  169.   
  170.                 int count = end - segstart;  
  171.                 for (int i = count - 1; i >= 0; i--) {  
  172.                     if (temp[i] == ch) {  
  173.                         recycle(temp);  
  174.                         return i + segstart;  
  175.                     }  
  176.                 }  
  177.   
  178.                 end = segstart;  
  179.             }  
  180.   
  181.             recycle(temp);  
  182.             return -1;  
  183.         }  
  184.   
  185.         for (int i = end - 1; i >= start; i--)  
  186.             if (s.charAt(i) == ch)  
  187.                 return i;  
  188.   
  189.         return -1;  
  190.     }  
  191.   
  192.     public static int indexOf(CharSequence s, CharSequence needle) {  
  193.         return indexOf(s, needle, 0, s.length());  
  194.     }  
  195.   
  196.     public static int indexOf(CharSequence s, CharSequence needle, int start) {  
  197.         return indexOf(s, needle, start, s.length());  
  198.     }  
  199.   
  200.     public static int indexOf(CharSequence s, CharSequence needle,  
  201.                               int start, int end) {  
  202.         int nlen = needle.length();  
  203.         if (nlen == 0)  
  204.             return start;  
  205.   
  206.         char c = needle.charAt(0);  
  207.   
  208.         for (;;) {  
  209.             start = indexOf(s, c, start);  
  210.             if (start > end - nlen) {  
  211.                 break;  
  212.             }  
  213.   
  214.             if (start < 0) {  
  215.                 return -1;  
  216.             }  
  217.   
  218.             if (regionMatches(s, start, needle, 0, nlen)) {  
  219.                 return start;  
  220.             }  
  221.   
  222.             start++;  
  223.         }  
  224.         return -1;  
  225.     }  
  226.   
  227.     public static boolean regionMatches(CharSequence one, int toffset,  
  228.                                         CharSequence two, int ooffset,  
  229.                                         int len) {  
  230.         char[] temp = obtain(2 * len);  
  231.   
  232.         getChars(one, toffset, toffset + len, temp, 0);  
  233.         getChars(two, ooffset, ooffset + len, temp, len);  
  234.   
  235.         boolean match = true;  
  236.         for (int i = 0; i < len; i++) {  
  237.             if (temp[i] != temp[i + len]) {  
  238.                 match = false;  
  239.                 break;  
  240.             }  
  241.         }  
  242.   
  243.         recycle(temp);  
  244.         return match;  
  245.     }  
  246.   
  247.     /** 
  248.      * Create a new String object containing the given range of characters 
  249.      * from the source string.  This is different than simply calling 
  250.      * {@link CharSequence#subSequence(int, int) CharSequence.subSequence} 
  251.      * in that it does not preserve any style runs in the source sequence, 
  252.      * allowing a more efficient implementation. 
  253.      */  
  254.     public static String substring(CharSequence source, int start, int end) {  
  255.         if (source instanceof String)  
  256.             return ((String) source).substring(start, end);  
  257.         if (source instanceof StringBuilder)  
  258.             return ((StringBuilder) source).substring(start, end);  
  259.         if (source instanceof StringBuffer)  
  260.             return ((StringBuffer) source).substring(start, end);  
  261.   
  262.         char[] temp = obtain(end - start);  
  263.         getChars(source, start, end, temp, 0);  
  264.         String ret = new String(temp, 0, end - start);  
  265.         recycle(temp);  
  266.   
  267.         return ret;  
  268.     }  
  269.   
  270.     /** 
  271.      * Returns list of multiple {@link CharSequence} joined into a single 
  272.      * {@link CharSequence} separated by localized delimiter such as ", ". 
  273.      * 
  274.      * @hide 
  275.      */  
  276.     public static CharSequence join(Iterable list) {  
  277.         final CharSequence delimiter = Resources.getSystem().getText(R.string.list_delimeter);  
  278.         return join(delimiter, list);  
  279.     }  
  280.   
  281.     /** 
  282.      * Returns a string containing the tokens joined by delimiters. 
  283.      * @param tokens an array objects to be joined. Strings will be formed from 
  284.      *     the objects by calling object.toString(). 
  285.      */  
  286.     public static String join(CharSequence delimiter, Object[] tokens) {  
  287.         StringBuilder sb = new StringBuilder();  
  288.         boolean firstTime = true;  
  289.         for (Object token: tokens) {  
  290.             if (firstTime) {  
  291.                 firstTime = false;  
  292.             } else {  
  293.                 sb.append(delimiter);  
  294.             }  
  295.             sb.append(token);  
  296.         }  
  297.         return sb.toString();  
  298.     }  
  299.   
  300.     /** 
  301.      * Returns a string containing the tokens joined by delimiters. 
  302.      * @param tokens an array objects to be joined. Strings will be formed from 
  303.      *     the objects by calling object.toString(). 
  304.      */  
  305.     public static String join(CharSequence delimiter, Iterable tokens) {  
  306.         StringBuilder sb = new StringBuilder();  
  307.         boolean firstTime = true;  
  308.         for (Object token: tokens) {  
  309.             if (firstTime) {  
  310.                 firstTime = false;  
  311.             } else {  
  312.                 sb.append(delimiter);  
  313.             }  
  314.             sb.append(token);  
  315.         }  
  316.         return sb.toString();  
  317.     }  
  318.   
  319.     /** 
  320.      * String.split() returns [''] when the string to be split is empty. This returns []. This does 
  321.      * not remove any empty strings from the result. For example split("a,", ","  ) returns {"a", ""}. 
  322.      * 
  323.      * @param text the string to split 
  324.      * @param expression the regular expression to match 
  325.      * @return an array of strings. The array will be empty if text is empty 
  326.      * 
  327.      * @throws NullPointerException if expression or text is null 
  328.      */  
  329.     public static String[] split(String text, String expression) {  
  330.         if (text.length() == 0) {  
  331.             return EMPTY_STRING_ARRAY;  
  332.         } else {  
  333.             return text.split(expression, -1);  
  334.         }  
  335.     }  
  336.   
  337.     /** 
  338.      * Splits a string on a pattern. String.split() returns [''] when the string to be 
  339.      * split is empty. This returns []. This does not remove any empty strings from the result. 
  340.      * @param text the string to split 
  341.      * @param pattern the regular expression to match 
  342.      * @return an array of strings. The array will be empty if text is empty 
  343.      * 
  344.      * @throws NullPointerException if expression or text is null 
  345.      */  
  346.     public static String[] split(String text, Pattern pattern) {  
  347.         if (text.length() == 0) {  
  348.             return EMPTY_STRING_ARRAY;  
  349.         } else {  
  350.             return pattern.split(text, -1);  
  351.         }  
  352.     }  
  353.   
  354.     /** 
  355.      * An interface for splitting strings according to rules that are opaque to the user of this 
  356.      * interface. This also has less overhead than split, which uses regular expressions and 
  357.      * allocates an array to hold the results. 
  358.      * 
  359.      * 

    The most efficient way to use this class is: 

  360.      * 
  361.      * 
     
  362.      * // Once 
  363.      * TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(delimiter); 
  364.      * 
  365.      * // Once per string to split 
  366.      * splitter.setString(string); 
  367.      * for (String s : splitter) { 
  368.      *     ... 
  369.      * } 
  370.      *  
  371.      */  
  372.     public interface StringSplitter extends Iterable {  
  373.         public void setString(String string);  
  374.     }  
  375.   
  376.     /** 
  377.      * A simple string splitter. 
  378.      * 
  379.      * 

    If the final character in the string to split is the delimiter then no empty string will 

  380.      * be returned for the empty string after that delimeter. That is, splitting "a,b," on 
  381.      * comma will return "a", "b", not "a", "b", "". 
  382.      */  
  383.     public static class SimpleStringSplitter implements StringSplitter, Iterator {  
  384.         private String mString;  
  385.         private char mDelimiter;  
  386.         private int mPosition;  
  387.         private int mLength;  
  388.   
  389.         /** 
  390.          * Initializes the splitter. setString may be called later. 
  391.          * @param delimiter the delimeter on which to split 
  392.          */  
  393.         public SimpleStringSplitter(char delimiter) {  
  394.             mDelimiter = delimiter;  
  395.         }  
  396.   
  397.         /** 
  398.          * Sets the string to split 
  399.          * @param string the string to split 
  400.          */  
  401.         public void setString(String string) {  
  402.             mString = string;  
  403.             mPosition = 0;  
  404.             mLength = mString.length();  
  405.         }  
  406.   
  407.         public Iterator iterator() {  
  408.             return this;  
  409.         }  
  410.   
  411.         public boolean hasNext() {  
  412.             return mPosition < mLength;  
  413.         }  
  414.   
  415.         public String next() {  
  416.             int end = mString.indexOf(mDelimiter, mPosition);  
  417.             if (end == -1) {  
  418.                 end = mLength;  
  419.             }  
  420.             String nextString = mString.substring(mPosition, end);  
  421.             mPosition = end + 1// Skip the delimiter.  
  422.             return nextString;  
  423.         }  
  424.   
  425.         public void remove() {  
  426.             throw new UnsupportedOperationException();  
  427.         }  
  428.     }  
  429.   
  430.     public static CharSequence stringOrSpannedString(CharSequence source) {  
  431.         if (source == null)  
  432.             return null;  
  433.         if (source instanceof SpannedString)  
  434.             return source;  
  435.         if (source instanceof Spanned)  
  436.             return new SpannedString(source);  
  437.   
  438.         return source.toString();  
  439.     }  
  440.   
  441.     /** 
  442.      * Returns true if the string is null or 0-length. 
  443.      * @param str the string to be examined 
  444.      * @return true if str is null or zero length 
  445.      */  
  446.     public static boolean isEmpty(CharSequence str) {  
  447.         if (str == null || str.length() == 0)  
  448.             return true;  
  449.         else  
  450.             return false;  
  451.     }  
  452.   
  453.     /** 
  454.      * Returns the length that the specified CharSequence would have if 
  455.      * spaces and control characters were trimmed from the start and end, 
  456.      * as by {@link String#trim}. 
  457.      */  
  458.     public static int getTrimmedLength(CharSequence s) {  
  459.         int len = s.length();  
  460.   
  461.         int start = 0;  
  462.         while (start < len && s.charAt(start) <= ' ') {  
  463.             start++;  
  464.         }  
  465.   
  466.         int end = len;  
  467.         while (end > start && s.charAt(end - 1) <= ' ') {  
  468.             end--;  
  469.         }  
  470.   
  471.         return end - start;  
  472.     }  
  473.   
  474.     /** 
  475.      * Returns true if a and b are equal, including if they are both null. 
  476.      * 

    Note: In platform versions 1.1 and earlier, this method only worked well if 

  477.      * both the arguments were instances of String.

     
  478.      * @param a first CharSequence to check 
  479.      * @param b second CharSequence to check 
  480.      * @return true if a and b are equal 
  481.      */  
  482.     public static boolean equals(CharSequence a, CharSequence b) {  
  483.         if (a == b) return true;  
  484.         int length;  
  485.         if (a != null && b != null && (length = a.length()) == b.length()) {  
  486.             if (a instanceof String && b instanceof String) {  
  487.                 return a.equals(b);  
  488.             } else {  
  489.                 for (int i = 0; i < length; i++) {  
  490.                     if (a.charAt(i) != b.charAt(i)) return false;  
  491.                 }  
  492.                 return true;  
  493.             }  
  494.         }  
  495.         return false;  
  496.     }  
  497.   
  498.     // XXX currently this only reverses chars, not spans  
  499.     public static CharSequence getReverse(CharSequence source,  
  500.                                           int start, int end) {  
  501.         return new Reverser(source, start, end);  
  502.     }  
  503.   
  504.     private static class Reverser  
  505.     implements CharSequence, GetChars  
  506.     {  
  507.         public Reverser(CharSequence source, int start, int end) {  
  508.             mSource = source;  
  509.             mStart = start;  
  510.             mEnd = end;  
  511.         }  
  512.   
  513.         public int length() {  
  514.             return mEnd - mStart;  
  515.         }  
  516.   
  517.         public CharSequence subSequence(int start, int end) {  
  518.             char[] buf = new char[end - start];  
  519.   
  520.             getChars(start, end, buf, 0);  
  521.             return new String(buf);  
  522.         }  
  523.   
  524.         @Override  
  525.         public String toString() {  
  526.             return subSequence(0, length()).toString();  
  527.         }  
  528.   
  529.         public char charAt(int off) {  
  530.             return AndroidCharacter.getMirror(mSource.charAt(mEnd - 1 - off));  
  531.         }  
  532.   
  533.         public void getChars(int start, int end, char[] dest, int destoff) {  
  534.             TextUtils.getChars(mSource, start + mStart, end + mStart,  
  535.                                dest, destoff);  
  536.             AndroidCharacter.mirror(dest, 0, end - start);  
  537.   
  538.             int len = end - start;  
  539.             int n = (end - start) / 2;  
  540.             for (int i = 0; i < n; i++) {  
  541.                 char tmp = dest[destoff + i];  
  542.   
  543.                 dest[destoff + i] = dest[destoff + len - i - 1];  
  544.                 dest[destoff + len - i - 1] = tmp;  
  545.             }  
  546.         }  
  547.   
  548.         private CharSequence mSource;  
  549.         private int mStart;  
  550.         private int mEnd;  
  551.     }  
  552.   
  553.     /** @hide */  
  554.     public static final int ALIGNMENT_SPAN = 1;  
  555.     /** @hide */  
  556.     public static final int FIRST_SPAN = ALIGNMENT_SPAN;  
  557.     /** @hide */  
  558.     public static final int FOREGROUND_COLOR_SPAN = 2;  
  559.     /** @hide */  
  560.     public static final int RELATIVE_SIZE_SPAN = 3;  
  561.     /** @hide */  
  562.     public static final int SCALE_X_SPAN = 4;  
  563.     /** @hide */  
  564.     public static final int STRIKETHROUGH_SPAN = 5;  
  565.     /** @hide */  
  566.     public static final int UNDERLINE_SPAN = 6;  
  567.     /** @hide */  
  568.     public static final int STYLE_SPAN = 7;  
  569.     /** @hide */  
  570.     public static final int BULLET_SPAN = 8;  
  571.     /** @hide */  
  572.     public static final int QUOTE_SPAN = 9;  
  573.     /** @hide */  
  574.     public static final int LEADING_MARGIN_SPAN = 10;  
  575.     /** @hide */  
  576.     public static final int URL_SPAN = 11;  
  577.     /** @hide */  
  578.     public static final int BACKGROUND_COLOR_SPAN = 12;  
  579.     /** @hide */  
  580.     public static final int TYPEFACE_SPAN = 13;  
  581.     /** @hide */  
  582.     public static final int SUPERSCRIPT_SPAN = 14;  
  583.     /** @hide */  
  584.     public static final int SUBSCRIPT_SPAN = 15;  
  585.     /** @hide */  
  586.     public static final int ABSOLUTE_SIZE_SPAN = 16;  
  587.     /** @hide */  
  588.     public static final int TEXT_APPEARANCE_SPAN = 17;  
  589.     /** @hide */  
  590.     public static final int ANNOTATION = 18;  
  591.     /** @hide */  
  592.     public static final int SUGGESTION_SPAN = 19;  
  593.     /** @hide */  
  594.     public static final int SPELL_CHECK_SPAN = 20;  
  595.     /** @hide */  
  596.     public static final int SUGGESTION_RANGE_SPAN = 21;  
  597.     /** @hide */  
  598.     public static final int EASY_EDIT_SPAN = 22;  
  599.     /** @hide */  
  600.     public static final int LOCALE_SPAN = 23;  
  601.     /** @hide */  
  602.     public static final int LAST_SPAN = LOCALE_SPAN;  
  603.   
  604.     /** 
  605.      * Flatten a CharSequence and whatever styles can be copied across processes 
  606.      * into the parcel. 
  607.      */  
  608.     public static void writeToParcel(CharSequence cs, Parcel p,  
  609.             int parcelableFlags) {  
  610.         if (cs instanceof Spanned) {  
  611.             p.writeInt(0);  
  612.             p.writeString(cs.toString());  
  613.   
  614.             Spanned sp = (Spanned) cs;  
  615.             Object[] os = sp.getSpans(0, cs.length(), Object.class);  
  616.   
  617.             // note to people adding to this: check more specific types  
  618.             // before more generic types.  also notice that it uses  
  619.             // "if" instead of "else if" where there are interfaces  
  620.             // so one object can be several.  
  621.   
  622.             for (int i = 0; i < os.length; i++) {  
  623.                 Object o = os[i];  
  624.                 Object prop = os[i];  
  625.   
  626.                 if (prop instanceof CharacterStyle) {  
  627.                     prop = ((CharacterStyle) prop).getUnderlying();  
  628.                 }  
  629.   
  630.                 if (prop instanceof ParcelableSpan) {  
  631.                     ParcelableSpan ps = (ParcelableSpan)prop;  
  632.                     int spanTypeId = ps.getSpanTypeId();  
  633.                     if (spanTypeId < FIRST_SPAN || spanTypeId > LAST_SPAN) {  
  634.                         Log.e(TAG, "external class \"" + ps.getClass().getSimpleName()  
  635.                                 + "\" is attempting to use the frameworks-only ParcelableSpan"  
  636.                                 + " interface");  
  637.                     } else {  
  638.                         p.writeInt(spanTypeId);  
  639.                         ps.writeToParcel(p, parcelableFlags);  
  640.                         writeWhere(p, sp, o);  
  641.                     }  
  642.                 }  
  643.             }  
  644.   
  645.             p.writeInt(0);  
  646.         } else {  
  647.             p.writeInt(1);  
  648.             if (cs != null) {  
  649.                 p.writeString(cs.toString());  
  650.             } else {  
  651.                 p.writeString(null);  
  652.             }  
  653.         }  
  654.     }  
  655.   
  656.     private static void writeWhere(Parcel p, Spanned sp, Object o) {  
  657.         p.writeInt(sp.getSpanStart(o));  
  658.         p.writeInt(sp.getSpanEnd(o));  
  659.         p.writeInt(sp.getSpanFlags(o));  
  660.     }  
  661.   
  662.     public static final Parcelable.Creator CHAR_SEQUENCE_CREATOR  
  663.             = new Parcelable.Creator() {  
  664.         /** 
  665.          * Read and return a new CharSequence, possibly with styles, 
  666.          * from the parcel. 
  667.          */  
  668.         public CharSequence createFromParcel(Parcel p) {  
  669.             int kind = p.readInt();  
  670.   
  671.             String string = p.readString();  
  672.             if (string == null) {  
  673.                 return null;  
  674.             }  
  675.   
  676.             if (kind == 1) {  
  677.                 return string;  
  678.             }  
  679.   
  680.             SpannableString sp = new SpannableString(string);  
  681.   
  682.             while (true) {  
  683.                 kind = p.readInt();  
  684.   
  685.                 if (kind == 0)  
  686.                     break;  
  687.   
  688.                 switch (kind) {  
  689.                 case ALIGNMENT_SPAN:  
  690.                     readSpan(p, sp, new AlignmentSpan.Standard(p));  
  691.                     break;  
  692.   
  693.                 case FOREGROUND_COLOR_SPAN:  
  694.                     readSpan(p, sp, new ForegroundColorSpan(p));  
  695.                     break;  
  696.   
  697.                 case RELATIVE_SIZE_SPAN:  
  698.                     readSpan(p, sp, new RelativeSizeSpan(p));  
  699.                     break;  
  700.   
  701.                 case SCALE_X_SPAN:  
  702.                     readSpan(p, sp, new ScaleXSpan(p));  
  703.                     break;  
  704.   
  705.                 case STRIKETHROUGH_SPAN:  
  706.                     readSpan(p, sp, new StrikethroughSpan(p));  
  707.                     break;  
  708.   
  709.                 case UNDERLINE_SPAN:  
  710.                     readSpan(p, sp, new UnderlineSpan(p));  
  711.                     break;  
  712.   
  713.                 case STYLE_SPAN:  
  714.                     readSpan(p, sp, new StyleSpan(p));  
  715.                     break;  
  716.   
  717.                 case BULLET_SPAN:  
  718.                     readSpan(p, sp, new BulletSpan(p));  
  719.                     break;  
  720.   
  721.                 case QUOTE_SPAN:  
  722.                     readSpan(p, sp, new QuoteSpan(p));  
  723.                     break;  
  724.   
  725.                 case LEADING_MARGIN_SPAN:  
  726.                     readSpan(p, sp, new LeadingMarginSpan.Standard(p));  
  727.                 break;  
  728.   
  729.                 case URL_SPAN:  
  730.                     readSpan(p, sp, new URLSpan(p));  
  731.                     break;  
  732.   
  733.                 case BACKGROUND_COLOR_SPAN:  
  734.                     readSpan(p, sp, new BackgroundColorSpan(p));  
  735.                     break;  
  736.   
  737.                 case TYPEFACE_SPAN:  
  738.                     readSpan(p, sp, new TypefaceSpan(p));  
  739.                     break;  
  740.   
  741.                 case SUPERSCRIPT_SPAN:  
  742.                     readSpan(p, sp, new SuperscriptSpan(p));  
  743.                     break;  
  744.   
  745.                 case SUBSCRIPT_SPAN:  
  746.                     readSpan(p, sp, new SubscriptSpan(p));  
  747.                     break;  
  748.   
  749.                 case ABSOLUTE_SIZE_SPAN:  
  750.                     readSpan(p, sp, new AbsoluteSizeSpan(p));  
  751.                     break;  
  752.   
  753.                 case TEXT_APPEARANCE_SPAN:  
  754.                     readSpan(p, sp, new TextAppearanceSpan(p));  
  755.                     break;  
  756.   
  757.                 case ANNOTATION:  
  758.                     readSpan(p, sp, new Annotation(p));  
  759.                     break;  
  760.   
  761.                 case SUGGESTION_SPAN:  
  762.                     readSpan(p, sp, new SuggestionSpan(p));  
  763.                     break;  
  764.   
  765.                 case SPELL_CHECK_SPAN:  
  766.                     readSpan(p, sp, new SpellCheckSpan(p));  
  767.                     break;  
  768.   
  769.                 case SUGGESTION_RANGE_SPAN:  
  770.                     readSpan(p, sp, new SuggestionRangeSpan(p));  
  771.                     break;  
  772.   
  773.                 case EASY_EDIT_SPAN:  
  774.                     readSpan(p, sp, new EasyEditSpan(p));  
  775.                     break;  
  776.   
  777.                 case LOCALE_SPAN:  
  778.                     readSpan(p, sp, new LocaleSpan(p));  
  779.                     break;  
  780.   
  781.                 default:  
  782.                     throw new RuntimeException("bogus span encoding " + kind);  
  783.                 }  
  784.             }  
  785.   
  786.             return sp;  
  787.         }  
  788.   
  789.         public CharSequence[] newArray(int size)  
  790.         {  
  791.             return new CharSequence[size];  
  792.         }  
  793.     };  
  794.   
  795.     /** 
  796.      * Debugging tool to print the spans in a CharSequence.  The output will 
  797.      * be printed one span per line.  If the CharSequence is not a Spanned, 
  798.      * then the entire string will be printed on a single line. 
  799.      */  
  800.     public static void dumpSpans(CharSequence cs, Printer printer, String prefix) {  
  801.         if (cs instanceof Spanned) {  
  802.             Spanned sp = (Spanned) cs;  
  803.             Object[] os = sp.getSpans(0, cs.length(), Object.class);  
  804.   
  805.             for (int i = 0; i < os.length; i++) {  
  806.                 Object o = os[i];  
  807.                 printer.println(prefix + cs.subSequence(sp.getSpanStart(o),  
  808.                         sp.getSpanEnd(o)) + ": "  
  809.                         + Integer.toHexString(System.identityHashCode(o))  
  810.                         + " " + o.getClass().getCanonicalName()  
  811.                          + " (" + sp.getSpanStart(o) + "-" + sp.getSpanEnd(o)  
  812.                          + ") fl=#" + sp.getSpanFlags(o));  
  813.             }  
  814.         } else {  
  815.             printer.println(prefix + cs + ": (no spans)");  
  816.         }  
  817.     }  
  818.   
  819.     /** 
  820.      * Return a new CharSequence in which each of the source strings is 
  821.      * replaced by the corresponding element of the destinations. 
  822.      */  
  823.     public static CharSequence replace(CharSequence template,  
  824.                                        String[] sources,  
  825.                                        CharSequence[] destinations) {  
  826.         SpannableStringBuilder tb = new SpannableStringBuilder(template);  
  827.   
  828.         for (int i = 0; i < sources.length; i++) {  
  829.             int where = indexOf(tb, sources[i]);  
  830.   
  831.             if (where >= 0)  
  832.                 tb.setSpan(sources[i], where, where + sources[i].length(),  
  833.                            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);  
  834.         }  
  835.   
  836.         for (int i = 0; i < sources.length; i++) {  
  837.             int start = tb.getSpanStart(sources[i]);  
  838.             int end = tb.getSpanEnd(sources[i]);  
  839.   
  840.             if (start >= 0) {  
  841.                 tb.replace(start, end, destinations[i]);  
  842.             }  
  843.         }  
  844.   
  845.         return tb;  
  846.     }  
  847.   
  848.     /** 
  849.      * Replace instances of "^1", "^2", etc. in the 
  850.      * template CharSequence with the corresponding 
  851.      * values.  "^^" is used to produce a single caret in 
  852.      * the output.  Only up to 9 replacement values are supported, 
  853.      * "^10" will be produce the first replacement value followed by a 
  854.      * '0'. 
  855.      * 
  856.      * @param template the input text containing "^1"-style 
  857.      * placeholder values.  This object is not modified; a copy is 
  858.      * returned. 
  859.      * 
  860.      * @param values CharSequences substituted into the template.  The 
  861.      * first is substituted for "^1", the second for "^2", and so on. 
  862.      * 
  863.      * @return the new CharSequence produced by doing the replacement 
  864.      * 
  865.      * @throws IllegalArgumentException if the template requests a 
  866.      * value that was not provided, or if more than 9 values are 
  867.      * provided. 
  868.      */  
  869.     public static CharSequence expandTemplate(CharSequence template,  
  870.                                               CharSequence... values) {  
  871.         if (values.length > 9) {  
  872.             throw new IllegalArgumentException("max of 9 values are supported");  
  873.         }  
  874.   
  875.         SpannableStringBuilder ssb = new SpannableStringBuilder(template);  
  876.   
  877.         try {  
  878.             int i = 0;  
  879.             while (i < ssb.length()) {  
  880.                 if (ssb.charAt(i) == '^') {  
  881.                     char next = ssb.charAt(i+1);  
  882.                     if (next == '^') {  
  883.                         ssb.delete(i+1, i+2);  
  884.                         ++i;  
  885.                         continue;  
  886.                     } else if (Character.isDigit(next)) {  
  887.                         int which = Character.getNumericValue(next) - 1;  
  888.                         if (which < 0) {  
  889.                             throw new IllegalArgumentException(  
  890.                                 "template requests value ^" + (which+1));  
  891.                         }  
  892.                         if (which >= values.length) {  
  893.                             throw new IllegalArgumentException(  
  894.                                 "template requests value ^" + (which+1) +  
  895.                                 "; only " + values.length + " provided");  
  896.                         }  
  897.                         ssb.replace(i, i+2, values[which]);  
  898.                         i += values[which].length();  
  899.                         continue;  
  900.                     }  
  901.                 }  
  902.                 ++i;  
  903.             }  
  904.         } catch (IndexOutOfBoundsException ignore) {  
  905.             // happens when ^ is the last character in the string.  
  906.         }  
  907.         return ssb;  
  908.     }  
  909.   
  910.     public static int getOffsetBefore(CharSequence text, int offset) {  
  911.         if (offset == 0)  
  912.             return 0;  
  913.         if (offset == 1)  
  914.             return 0;  
  915.   
  916.         char c = text.charAt(offset - 1);  
  917.   
  918.         if (c >= '\uDC00' && c <= '\uDFFF') {  
  919.             char c1 = text.charAt(offset - 2);  
  920.   
  921.             if (c1 >= '\uD800' && c1 <= '\uDBFF')  
  922.                 offset -= 2;  
  923.             else  
  924.                 offset -= 1;  
  925.         } else {  
  926.             offset -= 1;  
  927.         }  
  928.   
  929.         if (text instanceof Spanned) {  
  930.             ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset,  
  931.                                                        ReplacementSpan.class);  
  932.   
  933.             for (int i = 0; i < spans.length; i++) {  
  934.                 int start = ((Spanned) text).getSpanStart(spans[i]);  
  935.                 int end = ((Spanned) text).getSpanEnd(spans[i]);  
  936.   
  937.                 if (start < offset && end > offset)  
  938.                     offset = start;  
  939.             }  
  940.         }  
  941.   
  942.         return offset;  
  943.     }  
  944.   
  945.     public static int getOffsetAfter(CharSequence text, int offset) {  
  946.         int len = text.length();  
  947.   
  948.         if (offset == len)  
  949.             return len;  
  950.         if (offset == len - 1)  
  951.             return len;  
  952.   
  953.         char c = text.charAt(offset);  
  954.   
  955.         if (c >= '\uD800' && c <= '\uDBFF') {  
  956.             char c1 = text.charAt(offset + 1);  
  957.   
  958.             if (c1 >= '\uDC00' && c1 <= '\uDFFF')  
  959.                 offset += 2;  
  960.             else  
  961.                 offset += 1;  
  962.         } else {  
  963.             offset += 1;  
  964.         }  
  965.   
  966.         if (text instanceof Spanned) {  
  967.             ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset,  
  968.                                                        ReplacementSpan.class);  
  969.   
  970.             for (int i = 0; i < spans.length; i++) {  
  971.                 int start = ((Spanned) text).getSpanStart(spans[i]);  
  972.                 int end = ((Spanned) text).getSpanEnd(spans[i]);  
  973.   
  974.                 if (start < offset && end > offset)  
  975.                     offset = end;  
  976.             }  
  977.         }  
  978.   
  979.         return offset;  
  980.     }  
  981.   
  982.     private static void readSpan(Parcel p, Spannable sp, Object o) {  
  983.         sp.setSpan(o, p.readInt(), p.readInt(), p.readInt());  
  984.     }  
  985.   
  986.     /** 
  987.      * Copies the spans from the region start...end in 
  988.      * source to the region 
  989.      * destoff...destoff+end-start in dest. 
  990.      * Spans in source that begin before start 
  991.      * or end after end but overlap this range are trimmed 
  992.      * as if they began at start or ended at end. 
  993.      * 
  994.      * @throws IndexOutOfBoundsException if any of the copied spans 
  995.      * are out of range in dest. 
  996.      */  
  997.     public static void copySpansFrom(Spanned source, int start, int end,  
  998.                                      Class kind,  
  999.                                      Spannable dest, int destoff) {  
  1000.         if (kind == null) {  
  1001.             kind = Object.class;  
  1002.         }  
  1003.   
  1004.         Object[] spans = source.getSpans(start, end, kind);  
  1005.   
  1006.         for (int i = 0; i < spans.length; i++) {  
  1007.             int st = source.getSpanStart(spans[i]);  
  1008.             int en = source.getSpanEnd(spans[i]);  
  1009.             int fl = source.getSpanFlags(spans[i]);  
  1010.   
  1011.             if (st < start)  
  1012.                 st = start;  
  1013.             if (en > end)  
  1014.                 en = end;  
  1015.   
  1016.             dest.setSpan(spans[i], st - start + destoff, en - start + destoff,  
  1017.                          fl);  
  1018.         }  
  1019.     }  
  1020.   
  1021.     public enum TruncateAt {  
  1022.         START,  
  1023.         MIDDLE,  
  1024.         END,  
  1025.         MARQUEE,  
  1026.         /** 
  1027.          * @hide 
  1028.          */  
  1029.         END_SMALL  
  1030.     }  
  1031.   
  1032.     public interface EllipsizeCallback {  
  1033.         /** 
  1034.          * This method is called to report that the specified region of 
  1035.          * text was ellipsized away by a call to {@link #ellipsize}. 
  1036.          */  
  1037.         public void ellipsized(int start, int end);  
  1038.     }  
  1039.   
  1040.     /** 
  1041.      * Returns the original text if it fits in the specified width 
  1042.      * given the properties of the specified Paint, 
  1043.      * or, if it does not fit, a truncated 
  1044.      * copy with ellipsis character added at the specified edge or center. 
  1045.      */  
  1046.     public static CharSequence ellipsize(CharSequence text,  
  1047.                                          TextPaint p,  
  1048.                                          float avail, TruncateAt where) {  
  1049.         return ellipsize(text, p, avail, where, falsenull);  
  1050.     }  
  1051.   
  1052.     /** 
  1053.      * Returns the original text if it fits in the specified width 
  1054.      * given the properties of the specified Paint, 
  1055.      * or, if it does not fit, a copy with ellipsis character added 
  1056.      * at the specified edge or center. 
  1057.      * If preserveLength is specified, the returned copy 
  1058.      * will be padded with zero-width spaces to preserve the original 
  1059.      * length and offsets instead of truncating. 
  1060.      * If callback is non-null, it will be called to 
  1061.      * report the start and end of the ellipsized range.  TextDirection 
  1062.      * is determined by the first strong directional character. 
  1063.      */  
  1064.     public static CharSequence ellipsize(CharSequence text,  
  1065.                                          TextPaint paint,  
  1066.                                          float avail, TruncateAt where,  
  1067.                                          boolean preserveLength,  
  1068.                                          EllipsizeCallback callback) {  
  1069.   
  1070.         final String ellipsis = (where == TruncateAt.END_SMALL) ?  
  1071.                 Resources.getSystem().getString(R.string.ellipsis_two_dots) :  
  1072.                 Resources.getSystem().getString(R.string.ellipsis);  
  1073.   
  1074.         return ellipsize(text, paint, avail, where, preserveLength, callback,  
  1075.                 TextDirectionHeuristics.FIRSTSTRONG_LTR,  
  1076.                 ellipsis);  
  1077.     }  
  1078.   
  1079.     /** 
  1080.      * Returns the original text if it fits in the specified width 
  1081.      * given the properties of the specified Paint, 
  1082.      * or, if it does not fit, a copy with ellipsis character added 
  1083.      * at the specified edge or center. 
  1084.      * If preserveLength is specified, the returned copy 
  1085.      * will be padded with zero-width spaces to preserve the original 
  1086.      * length and offsets instead of truncating. 
  1087.      * If callback is non-null, it will be called to 
  1088.      * report the start and end of the ellipsized range. 
  1089.      * 
  1090.      * @hide 
  1091.      */  
  1092.     public static CharSequence ellipsize(CharSequence text,  
  1093.             TextPaint paint,  
  1094.             float avail, TruncateAt where,  
  1095.             boolean preserveLength,  
  1096.             EllipsizeCallback callback,  
  1097.             TextDirectionHeuristic textDir, String ellipsis) {  
  1098.   
  1099.         int len = text.length();  
  1100.   
  1101.         MeasuredText mt = MeasuredText.obtain();  
  1102.         try {  
  1103.             float width = setPara(mt, paint, text, 0, text.length(), textDir);  
  1104.   
  1105.             if (width <= avail) {  
  1106.                 if (callback != null) {  
  1107.                     callback.ellipsized(00);  
  1108.                 }  
  1109.   
  1110.                 return text;  
  1111.             }  
  1112.   
  1113.             // XXX assumes ellipsis string does not require shaping and  
  1114.             // is unaffected by style  
  1115.             float ellipsiswid = paint.measureText(ellipsis);  
  1116.             avail -= ellipsiswid;  
  1117.   
  1118.             int left = 0;  
  1119.             int right = len;  
  1120.             if (avail < 0) {  
  1121.                 // it all goes  
  1122.             } else if (where == TruncateAt.START) {  
  1123.                 right = len - mt.breakText(len, false, avail);  
  1124.             } else if (where == TruncateAt.END || where == TruncateAt.END_SMALL) {  
  1125.                 left = mt.breakText(len, true, avail);  
  1126.             } else {  
  1127.                 right = len - mt.breakText(len, false, avail / 2);  
  1128.                 avail -= mt.measure(right, len);  
  1129.                 left = mt.breakText(right, true, avail);  
  1130.             }  
  1131.   
  1132.             if (callback != null) {  
  1133.                 callback.ellipsized(left, right);  
  1134.             }  
  1135.   
  1136.             char[] buf = mt.mChars;  
  1137.             Spanned sp = text instanceof Spanned ? (Spanned) text : null;  
  1138.   
  1139.             int remaining = len - (right - left);  
  1140.             if (preserveLength) {  
  1141.                 if (remaining > 0) { // else eliminate the ellipsis too  
  1142.                     buf[left++] = ellipsis.charAt(0);  
  1143.                 }  
  1144.                 for (int i = left; i < right; i++) {  
  1145.                     buf[i] = ZWNBS_CHAR;  
  1146.                 }  
  1147.                 String s = new String(buf, 0, len);  
  1148.                 if (sp == null) {  
  1149.                     return s;  
  1150.                 }  
  1151.                 SpannableString ss = new SpannableString(s);  
  1152.                 copySpansFrom(sp, 0, len, Object.class, ss, 0);  
  1153.                 return ss;  
  1154.             }  
  1155.   
  1156.             if (remaining == 0) {  
  1157.                 return "";  
  1158.             }  
  1159.   
  1160.             if (sp == null) {  
  1161.                 StringBuilder sb = new StringBuilder(remaining + ellipsis.length());  
  1162.                 sb.append(buf, 0, left);  
  1163.                 sb.append(ellipsis);  
  1164.                 sb.append(buf, right, len - right);  
  1165.                 return sb.toString();  
  1166.             }  
  1167.   
  1168.             SpannableStringBuilder ssb = new SpannableStringBuilder();  
  1169.             ssb.append(text, 0, left);  
  1170.             ssb.append(ellipsis);  
  1171.             ssb.append(text, right, len);  
  1172.             return ssb;  
  1173.         } finally {  
  1174.             MeasuredText.recycle(mt);  
  1175.         }  
  1176.     }  
  1177.   
  1178.     /** 
  1179.      * Converts a CharSequence of the comma-separated form "Andy, Bob, 
  1180.      * Charles, David" that is too wide to fit into the specified width 
  1181.      * into one like "Andy, Bob, 2 more". 
  1182.      * 
  1183.      * @param text the text to truncate 
  1184.      * @param p the Paint with which to measure the text 
  1185.      * @param avail the horizontal width available for the text 
  1186.      * @param oneMore the string for "1 more" in the current locale 
  1187.      * @param more the string for "%d more" in the current locale 
  1188.      */  
  1189.     public static CharSequence commaEllipsize(CharSequence text,  
  1190.                                               TextPaint p, float avail,  
  1191.                                               String oneMore,  
  1192.                                               String more) {  
  1193.         return commaEllipsize(text, p, avail, oneMore, more,  
  1194.                 TextDirectionHeuristics.FIRSTSTRONG_LTR);  
  1195.     }  
  1196.   
  1197.     /** 
  1198.      * @hide 
  1199.      */  
  1200.     public static CharSequence commaEllipsize(CharSequence text, TextPaint p,  
  1201.          float avail, String oneMore, String more, TextDirectionHeuristic textDir) {  
  1202.   
  1203.         MeasuredText mt = MeasuredText.obtain();  
  1204.         try {  
  1205.             int len = text.length();  
  1206.             float width = setPara(mt, p, text, 0, len, textDir);  
  1207.             if (width <= avail) {  
  1208.                 return text;  
  1209.             }  
  1210.   
  1211.             char[] buf = mt.mChars;  
  1212.   
  1213.             int commaCount = 0;  
  1214.             for (int i = 0; i < len; i++) {  
  1215.                 if (buf[i] == ',') {  
  1216.                     commaCount++;  
  1217.                 }  
  1218.             }  
  1219.   
  1220.             int remaining = commaCount + 1;  
  1221.   
  1222.             int ok = 0;  
  1223.             String okFormat = "";  
  1224.   
  1225.             int w = 0;  
  1226.             int count = 0;  
  1227.             float[] widths = mt.mWidths;  
  1228.   
  1229.             MeasuredText tempMt = MeasuredText.obtain();  
  1230.             for (int i = 0; i < len; i++) {  
  1231.                 w += widths[i];  
  1232.   
  1233.                 if (buf[i] == ',') {  
  1234.                     count++;  
  1235.   
  1236.                     String format;  
  1237.                     // XXX should not insert spaces, should be part of string  
  1238.                     // XXX should use plural rules and not assume English plurals  
  1239.                     if (--remaining == 1) {  
  1240.                         format = " " + oneMore;  
  1241.                     } else {  
  1242.                         format = " " + String.format(more, remaining);  
  1243.                     }  
  1244.   
  1245.                     // XXX this is probably ok, but need to look at it more  
  1246.                     tempMt.setPara(format, 0, format.length(), textDir);  
  1247.                     float moreWid = tempMt.addStyleRun(p, tempMt.mLen, null);  
  1248.   
  1249.                     if (w + moreWid <= avail) {  
  1250.                         ok = i + 1;  
  1251.                         okFormat = format;  
  1252.                     }  
  1253.                 }  
  1254.             }  
  1255.             MeasuredText.recycle(tempMt);  
  1256.   
  1257.             SpannableStringBuilder out = new SpannableStringBuilder(okFormat);  
  1258.             out.insert(0, text, 0, ok);  
  1259.             return out;  
  1260.         } finally {  
  1261.             MeasuredText.recycle(mt);  
  1262.         }  
  1263.     }  
  1264.   
  1265.     private static float setPara(MeasuredText mt, TextPaint paint,  
  1266.             CharSequence text, int start, int end, TextDirectionHeuristic textDir) {  
  1267.   
  1268.         mt.setPara(text, start, end, textDir);  
  1269.   
  1270.         float width;  
  1271.         Spanned sp = text instanceof Spanned ? (Spanned) text : null;  
  1272.         int len = end - start;  
  1273.         if (sp == null) {  
  1274.             width = mt.addStyleRun(paint, len, null);  
  1275.         } else {  
  1276.             width = 0;  
  1277.             int spanEnd;  
  1278.             for (int spanStart = 0; spanStart < len; spanStart = spanEnd) {  
  1279.                 spanEnd = sp.nextSpanTransition(spanStart, len,  
  1280.                         MetricAffectingSpan.class);  
  1281.                 MetricAffectingSpan[] spans = sp.getSpans(  
  1282.                         spanStart, spanEnd, MetricAffectingSpan.class);  
  1283.                 spans = TextUtils.removeEmptySpans(spans, sp, MetricAffectingSpan.class);  
  1284.                 width += mt.addStyleRun(paint, spans, spanEnd - spanStart, null);  
  1285.             }  
  1286.         }  
  1287.   
  1288.         return width;  
  1289.     }  
  1290.   
  1291.     private static final char FIRST_RIGHT_TO_LEFT = '\u0590';  
  1292.   
  1293.     /* package */  
  1294.     static boolean doesNotNeedBidi(CharSequence s, int start, int end) {  
  1295.         for (int i = start; i < end; i++) {  
  1296.             if (s.charAt(i) >= FIRST_RIGHT_TO_LEFT) {  
  1297.                 return false;  
  1298.             }  
  1299.         }  
  1300.         return true;  
  1301.     }  
  1302.   
  1303.     /* package */  
  1304.     static 

更多相关文章

  1. Android(安卓)Studio——Android(安卓)TextUtils类介绍
  2. Android版本的RSA非对称加密实现
  3. [Android]Android字体高度的研究
  4. android 程序检测是否安装
  5. android 判断网络是否断开
  6. android XmlSerializer 组拼xml
  7. android 判断 网络 类型
  8. android 网络判断的几种方法
  9. 【Android】使用ConnectivityManager与NetworkInfo实现判断当前

随机推荐

  1. 与vanilla JS的Ajax请求正在退回200OK
  2. 维基百科,如在PHP中列出标题的索引
  3. php 显示某一个时间相当于当前时间在多少
  4. php默认有最大执行时间
  5. nginx + fastcgi  php配置下,安全的文件
  6. 如何使用变量访问多维数组中的某些元素?
  7. php 基本的常用字符串函数
  8. Laravel Migration - 创建从现有列填充
  9. 天气预报API接口大全
  10. 《Zend studio 12 + UPUPW+PHP5.4开发平