如何查找每行的 android TextView 字符数?

Posted

技术标签:

【中文标题】如何查找每行的 android TextView 字符数?【英文标题】:How to find android TextView number of characters per line? 【发布时间】:2011-08-23 15:51:12 【问题描述】:

所以我在 android 中有一个 TextView,其宽度与屏幕的整个长度相同,并且填充为 dip 5。如何计算适合屏幕上单行的字符数?我想换句话说,我正在尝试获取 textview 的列数?

我考虑过根据文本大小和宽度手动计算,但 1)不知道相关性和 2)由于以 dip 为单位的填充,不同的屏幕将使用不同数量的实际像素来填充。

总体问题:我试图用它来解决:如果给定一个字符串,我如何手动编辑到字符串,这样当 textview 逐个字符打印字符串时,我会知道何时开始一个不会的单词适合下一行。注意:我知道 textview 会自动将不适合的单词放到下一行,但是,由于我正在逐个字符打印,例如键入动画,textview 不知道该单词不适合,直到它打印出该单词的溢出字符。

一直在到处寻找这个...

谢谢!

添加的解决方案:

一种可能的解决方案:

public String measure2 (TextView t, String s) 
    String u = "";
    int start = 0;
    int end = 1;
    int space = 0;
    boolean ellipsized = false;
    float fwidth = t.getMeasuredWidth();
    for(;;) 
        //t.setText(s.substring(start, end));
        float twidth = t.getPaint().measureText(s.substring(start, end));
        if (twidth < fwidth)
            if (end < s.length())
                end++;
            else 
                if (!ellipsized)
                    return s;
                return u + s.subSequence(start, end);
            
        
        else 
            ellipsized = true;
            space = (u + s.substring(start, end)).lastIndexOf(" ");
            if (space == -1)
                space = end - 1;
            u += s.subSequence(start, space) + "\n";
            start = space + 1;
            end = start + 1;
        
    

解决方案 2,但有时仍使用解决方案 1:

public String measure3 (TextView t, String s) 
    List<String> wlist = Arrays.asList(s.split(" "));
    if (wlist.size() == 1)
        return measure2(t, s);
    String u = "";
    int end = 1;
    float fwidth = t.getMeasuredWidth();
    for(;;) 
        //t.setText(s.substring(start, end));
        if (wlist.isEmpty())
            return u;
        String temp = listStr(wlist, end);
        float twidth = t.getPaint().measureText(temp);
        if (twidth < fwidth)
            if (end < wlist.size())
                end++;
            else 
                return u + temp;
            
        
        else 
            temp = listStr(wlist, end-1);
            if (end == 1)
                temp = measure2(t, temp);
            if (wlist.isEmpty())
                return u + temp;
            else
                u = u + temp + "\n";
            wlist = wlist.subList(end - 1, wlist.size());
            end = 1;
        
    


public String listStr (List<String> arr, int end) 
    String s = "";
    for (String e : arr.subList(0, end) )
        s = s + e + " ";
    
    return s.trim();

我使用上面的代码生成了一个原始字符串 s,一个将被打印的字符串 u。但是,我认为这种方法非常低效。是否有另一种方法或更好的算法?注意:measure3 有一些错误我已经修复了,但是懒得编辑了

【问题讨论】:

我不认为默认字体是固定宽度的。因此,例如,它适合的 Ms 比 Is 少。如果您包含固定宽度的字体,那么找出的一种方法是继续添加到字符串并将其设置为视图,然后在屏幕上手动计算它们。它也会因不同的屏幕而有所不同,但这可能会导致您的使用出现问题。 我会看看这个问题***.com/questions/6272614/… @Derek 你能更新 measure3 函数吗?我想使用这个解决方案。谢谢 @Derek 最后我得到了解决方案,你也应该试试这个***.com/a/56753731/6676310 【参考方案1】:

我遇到了同样的问题,我通过 2 个步骤计算了每行的字符数: 第一步:计算行数

 val widthOfTvComment = widthOfScreen - marginLeft - marginRight
 var bounds  = Rect()
 var paint = Paint()
 paint.textSize = textSize
 paint.getTextBounds(comment,0,comment.length,bounds)

val lines = ( bounds.width()/widthOfTvComment)

第 2 步:计算每行的字符数

val charactersPerLine = comment.length / lines

【讨论】:

我相信这是一个近似值!【参考方案2】:

试试这个:

private boolean isTooLarge (TextView text, String newText) 
    float textWidth = text.getPaint().measureText(newText);
    return (textWidth >= text.getMeasuredWidth ());

由于字符的宽度可变,因此无法检测出适合多少字符。上述函数将测试特定字符串是否适合 TextView。 newText 的内容应该是特定行中的所有字符。如果为真,则开始新行(并使用新字符串作为参数传递)。


回复评论:

    因为该应用程序可以在许多系统中运行是正是您需要衡量它的原因。 这是一种解决“整体问题”的方法。使用str.size()&gt;numCol vs is too large 有什么区别?您需要实现动画(提示 #1:插入换行符) 正如我之前所说,当你开始一个新行时,你开始一个新字符串(提示 #2:如果你扩展 TextView,你可以在覆盖 setText 中实现所有这些)。 (提示 #3:跟踪使用 static int lines; 创建的行并使用 newString.split("\\r?\\n")[lines-1] 检查长度)。

【讨论】:

我正在设置字体大小,但由于我更喜欢​​在多个系统上使用该应用程序,因此我不会手动计算长度。此外,当第一次发生溢出时,您的 isTooLarge 可用于获取字符串的长度,但是,它仍然会使第一行受到 textview 的椭圆动画的影响。感谢您的帮助,但我需要一些东西来让我知道 textview 何时会为每一行变成椭圆。 @Derek I 回复太长,所以我添加到答案中 好的,所以我在我编辑的问题中发布了我的解决方案,有没有更有效的方法? @Derek - 首先,我看到您一次测量一个字符。您有兴趣知道整个单词是否适合,因此将字符串分成单词 (str.split(" ")) 并循环遍历单词。其次,首先测试功能。真的那么低效吗?您是否注意到任何延迟? 我明白你的意思,所以我做了 measure3,但是,我不知道为什么,但是即使你有一个没有空格的巨大字符串,textview 也会省略,所以 measure2 必须用于以下情况单个单词超出了宽度,但是 measure3 确实使用了 str.split(" ") ,这确实提高了效率。我意识到我在这个应用程序上所做的事情并没有滞后,因为它只读取短到中等的字符串,但是说我在另一个应用程序中使用这个功能,无论出于什么原因需要一本书的一章或一些巨大的东西,有没有更有效的代码还是这种唯一的方法?【参考方案3】:

您可以通过下面的代码获取Textview的总行并为每个字符获取字符串。然后您可以为每一行设置任何您想要的样式。

我将第一行设置为粗体。

private void setLayoutListner( final TextView textView ) 
        textView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() 
            @Override
            public void onGlobalLayout() 
                textView.getViewTreeObserver().removeGlobalOnLayoutListener(this);

                final Layout layout = textView.getLayout();

                // Loop over all the lines and do whatever you need with
                // the width of the line
                for (int i = 0; i < layout.getLineCount(); i++) 
                    int end = layout.getLineEnd(0);
                    SpannableString content = new SpannableString( textView.getText().toString() );
                    content.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, end, 0);
                    content.setSpan(new StyleSpan(android.graphics.Typeface.NORMAL), end, content.length(), 0);
                    textView.setText( content );
                
            
        );
    

试试这个方法。你可以用这种方法应用多种样式。

【讨论】:

以上是关于如何查找每行的 android TextView 字符数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在android中以编程方式查找TextView的文本区域(高度/宽度)

android:每行限制10个字符TextView

Android如何设置TextView的行间距行高

如何调整文字字距在Android的TextView的

如何调整文字字距在Android的TextView的

如何使用contextId使用'CLASS_NAME'查找'找到'android.widget.TextView':''multiple:fal