android - TextView.setText(),包含非常长的字符串和分页计算

时间:2014-10-23 16:25:26

标签: android pagination textview

我添加了一个scrollview(里面有textview)来填充整个屏幕。 我在textview中添加了一个很长的文本(书)。 Textview很不错,它知道如何将文本填充到整个屏幕,即处理换行符并知道每行放多少个单词,包括处理非英语单词。

根据总线,滚动视图高度和行高,我可以使用scrollview的scrollto快速移动到页面。

然而,当文本很长时,它非常慢并阻止UI线程。有人建议使用延迟加载方法,即textview的appendto。但是,通过这样做,我不知道有多少页面,并且不能长时间使用scrollto来“更改”页面。

我认为好几天但无法获得更好的解决方案。谁能给我一些想法和建议?感谢

2 个答案:

答案 0 :(得分:0)

基本上,一个巨大的ScrollView 挂断点,并且在切换之间变得很麻烦。更好的想法是将巨型文本/书籍分成页面,然后显示每个页面。换句话说:

  1. 获取一页/ TextView
  2. 中的文字数量
  3. 在正确的两个点之间分割文本[即,第一个点是页面的开头,第二个点是根据一页中的文本数量来计算的]
  4. 显示你喜欢的文字,虽然我个人更喜欢动态的ViewPager,我会每次计算上一页和下一页
  5. 这可以防止挂断,只要您在正确的时间策略性地计算上一页和下一页[即延迟加载或异步任务]。

    这可以帮助您实现分页: Pagination in Android TextView

    对于延迟加载的例子[比这些更简单,因为你只需要在另一个线程上将文本拆分成页面然后回馈那些格式化的页面]:

答案 1 :(得分:0)

一年多以前,我一直在寻找同样的该死的东西。并最终自己实现它。

行的宽度是符号间空格(字距调整),符号之间的空格宽度,视图边界宽度的总和。

对于要使用的每对符号,

符号间空格(字距调整)是不同的。如果您的字体不是MONOSPACE,则WA和DA具有不同的空间。

对于空格来说,每对符号都是不同的。 左右边界相同,每个符号都不同。

所以我做了 - 为你的应用程序准备一个每个可能符号的数组(不是全部,但是那些可能出现在你提供给视图的文本中),然后计算每个符号的宽度。

HashMap<String, Integer[]> charMap = new HashMap<>();

        String defaultSet = "ҢңӨөөҮүёЁQWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm\"'[]{}\\./`~!@#$%^&**()_+`12\uFEFF3456«;789»0—-=:|<>?йцуке…нгшщзхъфывапролджэячсмитьбюЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,,–";
        String[] charArray = defaultSet.split("");
        Rect bounds = new Rect();
        for (String mChar : charArray) {
            if (mChar.length() == 0) {
                continue;
            }
            //textView.setText(mChar);
            textPaint.getTextBounds(String.valueOf(mChar), 0, 1, bounds);
            int height = bounds.height();
            int width = bounds.width();
            Integer[] size = {width, height};
            charMap.put(mChar, size);
        }

接下来是为每对符号获取字距,空白和边界值。每个方法中的最后一个参数是您在第一个代码框中计算的 charMap

  /**
 * Returns Bounds map for each symbol
 * @param charArray
 * @param textPaint
 * @param mCharMap
 * @return
 */

private HashMap<String, Integer> generateBoundsLeftMap(String[] charArray, TextPaint textPaint, HashMap<String, Integer[]> mCharMap){
    //individual letterspacing, and whitespace width.
    HashMap<String, Integer>  boundsMap= new HashMap<>();
    Rect bounds = new Rect();

    for(int i=1;i<charArray.length;i++){
        String mKeyChar=charArray[i];

        String testLine="skajd fnфыв";
        textPaint.getTextBounds(testLine,0,11,bounds);
        int testwidth=bounds.width();
        String checkLine= mKeyChar.concat(testLine).concat(mKeyChar);
        textPaint.getTextBounds(checkLine, 0, 13, bounds);
        boundsMap.put(charArray[i], bounds.left);
        MLog.sout("boundsleft", "" + bounds.left, true);
        MLog.sout("measuretext",""+textPaint.measureText(checkLine),true);
        MLog.sout("boundsright",""+(textPaint.measureText(checkLine)-testwidth-(mCharMap.get(mKeyChar)[0]*2)-bounds.left),true);

    }
    return boundsMap;
}

/**
 * Returns Bounds map for each symbol
 * @param charArray
 * @param textPaint
 * @param mCharMap
 * @return
 */

private HashMap<String, Integer> generateBoundsRightMap(String[] charArray, TextPaint textPaint,HashMap<String, Integer[]> mCharMap){
    //individual letterspacing, and whitespace width.
    HashMap<String, Integer>  boundsMap= new HashMap<>();
    Rect bounds=new Rect();

    for(int i=1;i<charArray.length;i++){
        String mKeyChar=charArray[i];

        String testLine="aba";
        String checkLine= mKeyChar.concat(testLine).concat(mKeyChar);
        textPaint.getTextBounds(checkLine, 0, 5, bounds);
        int testwidth=bounds.width();
        int boundsright =(int) textPaint.measureText(checkLine)-testwidth-bounds.left;
        boundsMap.put(charArray[i], boundsright);
    }
    return boundsMap;
}

/**
 * returns Pairs map. HashMap<String, HashMap<String,   Integer > >
 *                            char1           char2   letterspacing
 * @param charArray
 * @param textPaint
 * @return
 */
private HashMap<String, HashMap<String, Integer>> generateKerningPairs(String[] charArray, TextPaint textPaint, HashMap<String,Integer[]> mCharMap){
    //individual letterspacing, and whitespace width.
    HashMap<String, HashMap<String, Integer> > pairMap= new HashMap<>();
    Rect bounds=new Rect();
    int lineWidth;
    int interspaceWidth;
    for(int i=1;i<charArray.length;i++){
        String mKeyChar=charArray[i];
        HashMap<String , Integer> spaceMap=new HashMap<>();
        for(int z=1; z<charArray.length;z++){
            //getletterspacing
            String checkLine=mKeyChar.concat(charArray[z]);
            textPaint.getTextBounds(checkLine,0,2,bounds);
            lineWidth = bounds.width();
            interspaceWidth=lineWidth-(mCharMap.get(mKeyChar))[0] - (mCharMap.get(charArray[z]))[0];
            spaceMap.put(charArray[z], interspaceWidth);
        }
        pairMap.put(mKeyChar,spaceMap);
    }
    return pairMap;
}

/**
 * returns Pairs map. HashMap<String, HashMap<String,   Integer > >
 *                            char1           char2   letterspacing
 * @param charArray
 * @param textPaint
 * @return
 */
private HashMap<String, HashMap<String, Integer>> generateSpacePairs(String[] charArray, TextPaint textPaint, HashMap<String,Integer[]> mCharMap){
    //individual letterspacing, and whitespace width.
    HashMap<String, HashMap<String, Integer> > pairMap= new HashMap<>();
    Rect bounds=new Rect();
    int lineWidth;
    int spaceWidth;
    for(int i=1;i<charArray.length;i++){
        String mKeyChar=charArray[i];
        HashMap<String , Integer> spaceMap=new HashMap<>();
        for(int z=1; z<charArray.length;z++){
            //getletterspacing
            String checkLine=mKeyChar.concat(" ").concat(charArray[z]);
            textPaint.getTextBounds(checkLine,0,3,bounds);
            lineWidth = bounds.width();
            spaceWidth=lineWidth-(mCharMap.get(mKeyChar))[0] - (mCharMap.get(charArray[z]))[0];
            spaceMap.put(charArray[z], spaceWidth);
        }
        pairMap.put(mKeyChar,spaceMap);
    }
    return pairMap;
}

计算这些值需要LOOOONG时间,因此我为每个DPI(使用genymotion和更改屏幕密度)执行了一次,并将其保存到txt文件中的JSON中。 kernmap.txt spacemap.txt ... 等等。

您将这些文件放入资源文件夹,结构如下所示

资产/ DPI / 160 / kernmap.txt ... 资产/ DPI / 240 / kernmap.txt ... 等等。

从这一点开始 - 你不能使用你在开头

中没有放入默认设置字符串的符号
String defaultSet = "ҢңӨөөҮүёЁQWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm\"'[]{}\\./`~!@#$%^&**()_+`12\uFEFF3456«;789»0—-=:|<>?йцуке…нгшщзхъфывапролджэячсмитьбюЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,,–";

即使准备好所有地图,您也会遇到性能问题。我使用jni来计算页面长度。

下一步是什么?

你得到你的字符串,让我们说

"This is a test line provided by blabla"

采取&#34; T&#34;和&#34; h&#34; (前2个字符)

linewidth = boundsLeftmap.get(&#34; T&#34;)(你在地图中有它)+ widthofchars.get(&#34; T&#34;)+ kerningbetween.get(&#34; T& #34;)。得到(&#34; h&#34;)+等等。

使用JNI需要3-4秒才能处理并将80000个字符的字符串分解为完全适合您视图的页面。