【问题标题】:Make a certain part of a android-textview align to the right使 android-textview 的某个部分向右对齐
【发布时间】:2013-01-09 08:35:29
【问题描述】:

我有这个TextView。它的某些部分应该与左侧对齐,而某些部分应与右侧对齐。我将如何在 Java 中做到这一点?

基本上我希望第一行向左对齐,下一行向右对齐,依此类推。

有人知道吗?

编辑

我曾尝试使用 HTML,但当它不起作用时,我尝试了 spans。

html 尝试

textView.setText(Html.fromHtml("<p align=\"right\">THIS IS TO THE RIGHT</p>"));

这是跨度尝试

    String LeftText = "LEFT";
    String RightText = "RIGHT";

    final String resultText = LeftText + "  " + RightText;
    final SpannableString styledResultText = new SpannableString(resultText);
    styledResultText.setSpan(new AlignmentSpan.Standard(Alignment.ALIGN_OPPOSITE), LeftText.length() + 1, LeftText.length() + 2 +RightText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    textView.setText(styledResultText);

但它们似乎都不起作用。

【问题讨论】:

    标签: java android android-widget


    【解决方案1】:
    TextView resultTextView = new TextView(this);
    final String resultText = LeftText + "  " + RightText;
    final SpannableString styledResultText = new SpannableString(resultText);
    styledResultText.setSpan(new AlignmentSpan.Standard(Alignment.ALIGN_OPPOSITE)
        , LeftText.length() + 2
        , LeftText.length() + 2 + RightText.length()
        , Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    resultTextView.setText(styledResultText);
    

    Alignment.ALIGN_OPPOSITE is the equivalent for right side.

    Alignment.ALIGN_NORMAL is the equivalent for left side.

    【讨论】:

    • 嗯。它不向右对齐。 textview 中的重力重要吗?
    • @user1991905 的重力 TextView 在这里很重要。尽量不要在您的 xml 中的 TextView 中提供 android:gravity
    • 这仅适用于我使用带有跨度的整行,但不适用于部分。 :(
    • @WonderCsabo AlignmentSpan.Standard 是段落样式,因此您需要在 LeftText 中添加一个换行符(即 \n )以使 RightText 右对齐。 (我没有测试上面的特定示例)
    • 对我来说,我只能让它使用换行符“\n”而不是两个空格,并将 setSpan 的第二个参数设置为没有“+2”的 LeftText.length()。我已经尝试了许多组合,试图摆脱我不想要的换行符,但还没有找到令人满意的解决方案。
    【解决方案2】:

    这是一个适用于 Spannable 的解决方案,如果左右太宽,它们将在同一条线上重叠。由于使用 spannable 执行 Left/Right 技巧需要在 Left 和 Right 之间换行,我的解决方法是添加一个 spannable,将一个换行的行高减少为零(即重叠行),然后在之后恢复正常行高那个。

        String fullText = leftText + "\n " + rightText;     // only works if  linefeed between them! "\n ";
    
        int fullTextLength = fullText.length();
        int leftEnd = leftText.length();
        int rightTextLength = rightText.length();
    
        final SpannableString s = new SpannableString(fullText);
        AlignmentSpan alignmentSpan = new AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE);
        s.setSpan(alignmentSpan, leftEnd, fullTextLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        s.setSpan(new SetLineOverlap(true), 1, fullTextLength-2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        s.setSpan(new SetLineOverlap(false), fullTextLength-1, fullTextLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    

    我们有处理重叠线的小程序:

        private static class SetLineOverlap implements LineHeightSpan {
        private int originalBottom = 15;        // init value ignored
        private int originalDescent = 13;       // init value ignored
        private Boolean overlap;                // saved state
        private Boolean overlapSaved = false;   // ensure saved values only happen once
    
        SetLineOverlap(Boolean overlap) {
            this.overlap = overlap;
        }
    
        @Override
        public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v,
                                 Paint.FontMetricsInt fm) {
            if (overlap) {
                if (!overlapSaved) {
                    originalBottom = fm.bottom;
                    originalDescent = fm.descent;
                    overlapSaved = true;
                }
                fm.bottom += fm.top;
                fm.descent += fm.top;
            } else {
                // restore saved values
                fm.bottom = originalBottom;
                fm.descent = originalDescent;
                overlapSaved = false;
            }
        }
    }
    

    【讨论】:

    • 不错的技巧,但如果 leftText 长于 textview 中的 1 行(无换行)则不起作用
    【解决方案3】:

    感谢@Frank 的提示,但这已经足够了:

    public class LineOverlapSpan implements LineHeightSpan {
        @Override
        public void chooseHeight(final CharSequence text, final int start, final int end, final int spanstartv, final int v, final Paint.FontMetricsInt fm) {
            fm.bottom += fm.top;
            fm.descent += fm.top;
        }
    }
    

    这样使用:

    CharSequence text = return new Truss()
            .append("LEFT")
            .pushSpan(LineOverlapSpan())
            .append("\n")
            .popSpan()
            .pushSpan(AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE))
            .append("RIGHT")
            .build()
    

    Truss 在哪里

    一个SpannableStringBuilder 包装器,它的 API 不会让我想戳我的眼睛。

    【讨论】:

      【解决方案4】:

      两种解决方案:

      1) 为每一行设置不同的文本视图并设置其重心。

      2) 在加载数据时使用 Html 为其设置 html 中的对齐方式 REF:how-to-display-html-in-textview 这行不通 align is not a supported tags 编辑:

      还有

      3:将使用跨度。

      【讨论】:

      • 嗯,我认为使用 HTML 的第二种解决方案将是一个很好的方法,但它没有工作.. textView.setText(Html.fromHtml("

        这应该在右边

        "));
      • textView.setText(Html.fromHtml("

        这应该在右边

        "));您确定 html 的对齐方式也适用于 textview 吗?
      • 我只是尝试了一些示例并研究了HTML不支持对齐stackoverflow.com/questions/3874999/alignment-in-html-fromhtml
      • 是的,我也读到了.. 但是为什么 span 解决方案不起作用.. 应该可以,不是吗?
      【解决方案5】:

      简单。在文本视图中调整 xml 部分。使用布局。如果您希望文本视图位于左侧

      android:alignParentLeft="true" 更多对齐细节看这里。

      http://developer.android.com/reference/android/widget/RelativeLayout.LayoutParams.html

      这也是不同布局的示例。

      http://www.androidhive.info/2011/07/android-layouts-linear-layout-relative-layout-and-table-layout/

      【讨论】:

        【解决方案6】:

        启发了其他解决方案,但解决了多行文本问题和文本重叠问题

        class LineOverlapSpan() : LineHeightSpan {
            var originalBottom: Int = 0
            var originalDescent: Int = 0
            var overlapSaved = false
        
            override fun chooseHeight(
                text: CharSequence?,
                start: Int,
                end: Int,
                spanstartv: Int,
                v: Int,
                fm: Paint.FontMetricsInt?
            ) {
                if (fm == null) {
                    return
                }
        
                if (!overlapSaved) {
                    originalBottom = fm.bottom
                    originalDescent = fm.descent
                    overlapSaved = true
                }
        
                if (text?.subSequence(start, end)?.endsWith("\n") == true) {
                    fm.bottom += fm.top
                    fm.descent += fm.top
                } else {
                    fm.bottom = originalBottom
                    fm.descent = originalDescent
                }
            }
        
        }
        

        用法:

        fun keyValueSpan(key: CharSequence, value: CharSequence) = span {
            span {
                alignment = "normal"
                +key
                span {
                    textColor = Color.TRANSPARENT
                    +value
                }
                span {
                    +"\n"
                    addSpan(LineOverlapSpan())
                }
            }
            span {
                alignment = "opposite"
                +value
            }
        }
        

        Kotlin 解决方案正在使用 Kpan 库 https://github.com/2dxgujun/Kpan

        【讨论】:

        • 但是当您在左侧使用 BIG(比如说 24dp)文本然后在同一行中添加与右侧对齐的 10dp 文本时,它不能解决...它会剪切大文本底端 ?知道如何解决这个问题
        猜你喜欢
        • 2014-03-15
        • 1970-01-01
        • 2012-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多