【问题标题】:How to find android TextView number of characters per line?如何查找每行的 android TextView 字符数?
【发布时间】: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 少。如果您包含固定宽度的字体,那么找出的一种方法是继续添加到字符串并将其设置为视图,然后在屏幕上手动计算它们。它也会因不同的屏幕而有所不同,但这可能会导致您的使用出现问题。
  • 我会看看这个问题stackoverflow.com/questions/6272614/…
  • @Derek 你能更新 measure3 函数吗?我想使用这个解决方案。谢谢
  • @Derek 最后我得到了解决方案,你也应该试试这个stackoverflow.com/a/56753731/6676310

标签: android text size width textview


【解决方案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 的内容应该是特定行中的所有字符。如果为真,则开始新行(并使用新字符串作为参数传递)。


回复评论:

  1. 因为该应用程序可以在许多系统中运行是正是您需要衡量它的原因。
  2. 这是一种解决“整体问题”的方法。使用str.size()&gt;numCol vs is too large 有什么区别?您需要实现动画(提示 #1:插入换行符)
  3. 正如我之前所说,当你开始一个新行时,你开始一个新字符串(提示 #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 );
                }
            }
        });
    }

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-08
    • 1970-01-01
    • 1970-01-01
    • 2015-01-25
    • 2016-06-24
    • 2019-11-29
    • 2012-07-22
    • 1970-01-01
    相关资源
    最近更新 更多