【问题标题】:How to use custom ellipsis in Android TextView如何在 Android TextView 中使用自定义省略号
【发布时间】:2014-11-21 04:17:45
【问题描述】:

我有一个 maxlines=3 的 TextView,我想使用我自己的省略号,而不是

"Lore ipsum ..."

我需要

"Lore ipsum ... [See more]"

为了给用户一个提示,点击视图会展开全文。

有可能吗?

我正在考虑检查 TextView 是否有省略号,在这种情况下添加文本“[查看更多]”,然后在之前设置省略号,但我找不到这样做的方法。

也许如果我找到文本被剪切的位置,我可以禁用省略号并创建一个子字符串,然后添加“... [查看更多]”,但我不知道如何获得该位置。

【问题讨论】:

  • 参考l.getEllipsisStart()

标签: android textview ellipsis


【解决方案1】:

我终于以这种方式管理它(可能不是最好的):

private void setLabelAfterEllipsis(TextView textView, int labelId, int maxLines){

    if(textView.getLayout().getEllipsisCount(maxLines-1)==0) {
        return; // Nothing to do
    }

    int start = textView.getLayout().getLineStart(0);
    int end = textView.getLayout().getLineEnd(textView.getLineCount() - 1);
    String displayed = textView.getText().toString().substring(start, end);
    int displayedWidth = getTextWidth(displayed, textView.getTextSize());

    String strLabel = textView.getContext().getResources().getString(labelId);
    String ellipsis = "...";
    String suffix = ellipsis + strLabel;

    int textWidth;
    String newText = displayed;
    textWidth = getTextWidth(newText + suffix, textView.getTextSize());

    while(textWidth>displayedWidth){
        newText = newText.substring(0, newText.length()-1).trim();
        textWidth = getTextWidth(newText + suffix, textView.getTextSize());
    }

    textView.setText(newText + suffix);
}

private int getTextWidth(String text, float textSize){
    Rect bounds = new Rect();
    Paint paint = new Paint();
    paint.setTextSize(textSize);
    paint.getTextBounds(text, 0, text.length(), bounds);

    int width = (int) Math.ceil( bounds.width());
    return width;
}

【讨论】:

  • 而不是像ellipsis = "...";那样使用三个点,你应该使用水平省略号字符(…实体->
  • textView.getLayout() 返回 null
  • Android 使用TextUtils.ELLIPSIS_NORMAL[0] 表示标准省略号,解析为'\u2026'。这可以在 TextView 间接使用的 Layout#getEllipsisChar 方法中找到。
  • 尝试在recyclerView中使用这种方式。 textView.getLayout() 返回 null。是否需要进行任何修改才能使其对回收站/列表视图有用?
  • 如果 getLayout 为 null,则使用 ViewTreeObserver.OnGlobalLayoutListener。
【解决方案2】:

我认为来自@jmhostalet 的答案会降低性能(尤其是在处理列表和大量 TextView 时),因为 TextView 不止一次地绘制文本。我创建了一个自定义 TextView,它在 onMeasure() 中解决了这个问题,因此只绘制了一次文本。

我最初在这里发布了我的答案:https://stackoverflow.com/a/52589927/1680301

这里是回购的链接:https://github.com/TheCodeYard/EllipsizedTextView

【讨论】:

  • 是的,我正在这样做,在回收站视图中。它降低了整体性能,
【解决方案3】:

@George @jmhostalet 我在我的回收站视图中这样做,它降低了整体性能。 `

ViewTreeObserver vto = previewContent.getViewTreeObserver();
    vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                try {
                    Layout layout = previewContent.getLayout();
                    int index1 = layout.getLineStart(previewContent.getMaxLines());
                    if (index1 > 10 && index1 < ab.getPreviewContent().length()) {
                        String s =
                                previewContent.getText().toString().substring(0, index1 - 10);
                        previewContent
                                .setText(Html.fromHtml(
                                        s + "<font color='#DC5530'>...और पढ़ें</font>"));
                    }
                    return true;
                }catch (Exception e)
                {
                    Crashlytics.logException(e);
                }
                return true;
            }
        });` 

【讨论】:

    【解决方案4】:

    这是一个使用 Kotlin 扩展的好方法。 请注意,我们需要等待视图布局,然后才能测量和附加后缀。

    TextViewExtensions.kt

    fun TextView.setEllipsizedSuffix(maxLines: Int, suffix: String) {
        addOnLayoutChangeListener(object: View.OnLayoutChangeListener {
            override fun onLayoutChange(v: View?, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom:     Int) {
    
                val allText = text.toString()
                var newText = allText
                val tvWidth = width
                val textSize = textSize
    
                if(!TextUtil.textHasEllipsized(newText, tvWidth, textSize, maxLines)) return
    
                while (TextUtil.textHasEllipsized(newText, tvWidth, textSize, maxLines)) {
                    newText = newText.substring(0, newText.length - 1).trim()
                }
    
                //now replace the last few chars with the suffix if we can
                val endIndex = newText.length - suffix.length - 1 //minus 1 just to make sure we have enough room
                if(endIndex > 0) {
                    newText = "${newText.substring(0, endIndex).trim()}$suffix"
                }
    
                text = newText
    
                removeOnLayoutChangeListener(this)
            }
        })
    }
    

    TextUtil.kt

    fun textHasEllipsized(text: String, tvWidth: Int, textSize: Float, maxLines: Int): Boolean {
        val paint = Paint()
        paint.textSize = textSize
        val size = paint.measureText(text).toInt()
    
        return size > tvWidth * maxLines
    }
    

    然后像这样实际使用它 myTextView.setEllipsizedSuffix(2, "...See more")


    注意:如果您的文本来自服务器并且可能有换行符,那么您可以使用此方法来确定文本是否已省略。

    fun textHasEllipsized(text: String, tvWidth: Int, textSize: Float, maxLines: Int): Boolean {
        val paint = Paint()
        paint.textSize = textSize
        val size = paint.measureText(text).toInt()
        val newLineChars = StringUtils.countMatches(text, "\n")
    
        return size > tvWidth * maxLines || newLineChars >= maxLines
    }
    

    StringUtils 来自implementation 'org.apache.commons:commons-lang3:3.4'

    【讨论】:

      【解决方案5】:

      这是 Kotlin 的解决方案。

      yourTextView.post{} 是必需的,因为 textview 在渲染之前不会被椭圆化。

        val customSuffix = "... [See more]"
        yourTextView.post {
          if (yourTextView.layout.getEllipsisStart(-1) != -1) {
            val newText = yourTextView.text.removeRange(
                yourTextView.layout.getEllipsisStart(-1) - customSuffix.length, yourTextView.text.length
            )
            yourTextView.text = String.format("%s%s", newText, customSuffix)
          }
        }
      

      【讨论】:

      • 确保将yourTextView 替换为您要省略的文本视图。
      • 是的,我正在使用 textview。但在处理程序中使用时它正在工作
      • @Xenolion 我没有对它进行多线测试,但我看不出它有什么不工作的原因。
      • 我想到的原因是 layout.getEllipsisStart(line) 为您提供特定行的省略号开头,但不是所有文本!
      • 可能是。我会说试试看。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-07
      • 1970-01-01
      • 2021-09-20
      • 2011-09-17
      • 2016-10-23
      • 2013-09-15
      相关资源
      最近更新 更多