Android布局:包裹两个文本视图

10

我希望实现以下布局

AAAAAAAAAAAAAAAAAA
AAAAA... BBBBBBBBB

当 AAAA 是一个文本视图(ellipsize = "end")且 BBB 也是一个文本视图时。它永远不会超过两行,我只需要第一个文本视图包装在第二个文本视图周围。

我该怎么做呢?

Idea in screenshot


2
你的意思是要让BBB完全显示,并根据放置BBB后剩余的空间来换行AAA吗? - Lei Guo
我已经检查过了...我不认为这是重复的。 - Stephane Maarek
1
这个问题似乎不是重复的。原始问题 是关于单个TextView文本自动换行的问题。而这篇文章是关于如何让TextView1自动换行,并将TextView2保持在其右侧。因此,我提名重新打开这个问题。 - MysticMagicϡ
1
@Stephane 我明白了,B内容总是显示完整的,而A将被包装。 - rupesh
1
好的,我喜欢它,我会尝试实现它。 - Stephane Maarek
显示剩余5条评论
5个回答

2

最终结果

enter image description here

解释

这并不是完美的,可能需要一些微调才能满足您的需求。我省略了ellipsize部分,以使其更通用,但很容易为此调整代码。这个想法很简单,但我花了几个小时(只因为今天是星期天)才让它工作起来。我们计算第二个TextView中还有多少字符适合第一个TextView的最后一行。然后,使用该数字将最后一行添加到第二个TextView中,并使用与容器背景相匹配的颜色,这是一个限制,可能可以通过某种方式解决,但我似乎找不到。

有了这个,我们就可以使两个视图的文本对齐,但它们仍然不会重叠以允许换行效果。因此,我们获取文本的高度,并向第二个文本视图添加负边距,以使它们重叠,为确保第一个TextView在第二个TextView上方,我们需要调用bringToFront(),以避免将颜色与背景相同的文本覆盖在第一个文本视图的最后一行上(哇,这变得很混乱了)。由于字符可能占用更多空间,它可能无法很好地处理不同字体和字重(例如加粗)。

我没有将其制作成方法,但它可以很容易地变成通用且可重复使用的代码,只是想证明我是否能做到。以下是代码,供任何人享受和改进。布局只是一个容器(例如RelativeLayout)和两个具有ID firstsecond 的文本视图,我已将第二个文本视图的文本颜色设置为红色,以使其更清晰,但这并非必要。

代码

    final TextView first = (TextView) findViewById(R.id.textView);
    final TextView second = (TextView) findViewById(R.id.textView2);
    final ViewGroup container  = (ViewGroup)findViewById(R.id.container);
    final ViewTreeObserver obs = findViewById(R.id.container).getViewTreeObserver();

    obs.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            //Get characters from the first TextView's last line
            String lastLine = first.getText().toString().substring(first.getLayout().getLineStart(first.getLineCount() - 1));

            //Calculate the number of extra characters that will fit in the first one
            int e = 0; //Extra characters
            int lineCount = first.getLineCount();
            while (lineCount == first.getLineCount() && e < second.getText().toString().length() - 1) {
                first.append(second.getText().toString().substring(e, e + 1));
                e++;
            }

            //Remove those characters again to leave the first TextView as it was
            String firstString = first.getText().toString();
            first.setText(firstString.substring(0, firstString.length() - e));

            //Add the last line of the first textview to the second textview
            second.setText(Html.fromHtml("<font color='#F2F2F2'>"+lastLine+"</font>"+second.getText()));

            //add a negative margin to the second textview equal to a line's height
            ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) second.getLayoutParams();
            params.topMargin = -(int)(first.getLineHeight()+10);
            second.setLayoutParams(params);

            //Make sure first is on top
            first.bringToFront();

            //Remove the listener
            if (Build.VERSION.SDK_INT < 16) {
                container.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            } else {
                container.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        }
    });

1
在RelativeLayout中,使文本视图AAA成为普通的2行高文本视图,不使用省略号,并使文本视图BBB带有文本“... BBBBBBBB”和非透明背景,以便文本视图AAA不会出现在BBB后面。
第二种选择是通过编程计算字母数量,如果超过应该的长度,则将其缩短。
但如果不使用等宽字体,则这两种“hack”都无法100%正常工作。对我的英语表示抱歉。
<RelativeLayout android:layout_width="200dp" android:layout_height="70dp">

  <TextView android:id="@+id/aaa"
    android:layout_width="match_parent" android:layout="match_parent"
    android:lines="2"
    android:typeface="monospace" />

  <TextView android:id="@+id/bbb"
    android:layout_width="match_parent" android:layout="wrap_content"
    android:typeface="monospace"
    android:lines="1"
    android:background="#ffffffff"
    android:layout_alignParentRight="true"
    android:layout_alignParentBottom="true" />

</RelativeLayout>

你还需要计算 AAA 字符串中的字母数量,以及 BBB 字符串中的字母数量。如果这两个数量的总和超过了允许的范围(文本会重叠),则在 BBB 字符串之前添加“...”字符串。
BBBTextView = (TextView) findViewbyId(R.id.bbb);

int maxLetterCount = 125; // you need to specify this number
String AAAString = " gtgtfd  def e refrfecj gjv jvrji rf wj jiefijr jgfrjf jrf"
String BBBString = "deeded ed e ddd"

if ( (BBBString.length()+BBBString.length()) > maxLetterCount ) {
    BBBString = "... " + BBBString;
}

BBBTextView.setText(BBBString);

我使用Roboto字体,因此它不是等宽字体。我喜欢第一个想法。代码会是什么样子? - Stephane Maarek

0

-1

不使用任何库。

 <RelativeLayout
    android:layout_height="wrap_content"
    android:layout_width="fill_parent" >

    <TextView
        android:id="@+id/AAA"
        android:layout_toLeftOf="@+id/BBB"
        android:layout_height="wrap_content"
        android:maxLines="2"
        android:layout_width="match_parent" />

    <TextView
        android:id="@+id/BBB"
        android:layout_alignParentRight="true"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content" />
</RelativeLayout>

谢谢!这只有一行。那两行呢? - Stephane Maarek
你的TextView是否超过两行或已经达到最大值了? - waelhe
编程相关内容的翻译如下:2行是要求。可以占用一行或两行最多。 - Stephane Maarek
@Stephane:请查看新编辑的代码.. :D 之前,我忘记删除singleLine=true,所以它无法工作.. - waelhe
你的代码将会产生以下输出:AAAAAA AAAA..BBBBB好的,在注释中它不起作用,但是A文本不会覆盖B文本。它不会环绕... 不符合要求。 - Stephane Maarek
显示剩余2条评论

-2

你可以使用 HTML

myTextView.setText(Html.fromHtml("<p>Any html code</p>"));

请提供一些解释说明这个回答如何回答了该问题。 - Huangism

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接