【问题标题】:Android TextView Truncation Priority or Compression Resistance [duplicate]Android TextView截断优先级或抗压缩性[重复]
【发布时间】:2016-12-16 01:42:15
【问题描述】:

我在屏幕上水平放置 3 个视图(固定大小的图像和 2 个单行文本视图:leftTextViewrightTextView),我试图让 rightTextView 紧靠leftTextView,但如果两个标签的宽度都超过屏幕大小,请截断leftTextiew

所需功能示例:

|img|leftText|rightText|                ||(end of screen)
|img|leftTextMedium|rightText|          ||
|img|leftTextTooLongSoTrunc...|rightText||

实际情况:

|img|leftText|rightText|                ||(end of screen)
|img|leftTextPrettyLongButNotHuge|rightT||
|img|leftTextWhichIsIncrediblyLongBlahBl||

目前,如果两个文本视图的大小超过视图的宽度,rightTextView 最终会被压扁以腾出空间,即使我在 leftTextView 上设置了android:ellipsize="end"

有没有办法让leftTextView 具有“截断优先级”,如果它会导致其他视图不适合,它应该截断?或者另一方面,我可以将rightTextView 设置为具有“抗压性”,以防止它被挤压为leftTextView 腾出空间吗?这是我的 XML 示例:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/fixedWidthImage"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <TextView
        android:id="@+id/leftTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@+id/fixedWidthImage"
        android:layout_toRightOf="@id/fixedWidthImage"
        android:maxLines="1"
        android:textSize="18sp"
        android:ellipsize="end" />

    <TextView
        android:id="@+id/rightTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@+id/leftTextView"
        android:layout_toRightOf="@+id/leftTextView"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:maxLines="1"
        android:textSize="12sp" />

</RelativeLayout>

我尝试过的事情:

  1. leftTextView 中,添加toStartOf / toLeftOf rightTextView(使应用程序崩溃)
  2. 不要将rightTextViewleftTextView 的末尾/右侧对齐,而是将其翻转并将leftTextViewrightTextView 的开头/左侧对齐。这导致rightTextView 被锚定到屏幕的末尾,而不是直接在leftTextView 的右侧。最终结果的示例:

    |img|leftText                 |rightText||
    |img|leftTextMedium           |rightText||
    |img|leftTextTooLongSoTrunc...|rightText||
    
  3. 即使我设置android:minWidth="25dp" 只是为了确保rightTextView 的至少部分 是可见的(我不想这样做,因为这个文本长度是可变的)它最终仍会压缩宽度以为leftTextView 腾出空间。

  4. 根据Emanuel Moecklin 的回答,我尝试将LinearLayout 包装起来并在leftTextView 上设置权重。结果在视觉上与我在 #2 中尝试的相同。

【问题讨论】:

  • 在我为重复标记辩护时,在我问我的时候,其他问题没有答案。此外,它的标题很糟糕,这可能是我一开始没有意识到它存在的原因。

标签: android xml textview truncation


【解决方案1】:

您可以通过TableLayoutshrinkColumns 属性归档此布局。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <!-- Row 1 -->
    <TableLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:shrinkColumns="1">

        <TableRow
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_vertical">

            <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@mipmap/ic_launcher"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="end"
                    android:text="leftText"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="none"
                    android:text="rightText"/>
        </TableRow>

    </TableLayout>


    <!-- Row 2 -->
    <TableLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:shrinkColumns="1">

        <TableRow
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_vertical">

            <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@mipmap/ic_launcher"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="end"
                    android:text="leftTextPrettyLongButNotHuge"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="none"
                    android:text="rightText"/>
        </TableRow>

    </TableLayout>

    <!-- Row 3 -->
    <TableLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:shrinkColumns="1">

        <TableRow
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_vertical">

            <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@mipmap/ic_launcher"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="end"
                    android:text="leftTextWhichIsIncrediblyLongBlahBlahBlahBlah"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="none"
                    android:text="rightText"/>
        </TableRow>

    </TableLayout>

</LinearLayout>

【讨论】:

  • 垂直布局可以这样做吗?我需要将 TableRow 中的项目垂直对齐并设置 android:shrinkColumns="0" 以缩小第一个视图。
  • 设置android:shrinkColumns="0"工作正常。
  • 如何使用 ConstraintLayout 做到这一点?
【解决方案2】:

只需在左侧 textView 中使用 android:maxWidth 属性即可。所以,你的左视图永远不会超过这个限制。并且总会有空间让您的右视图。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/fixedWidthImage"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:src="@drawable/ic_launcher" />

    <TextView
        android:id="@+id/leftTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toEndOf="@+id/fixedWidthImage"
        android:layout_toRightOf="@+id/fixedWidthImage"
        android:ellipsize="end"
        android:lines="1"
        android:maxWidth="250dp"
        android:text="This is a Long left Text which never ends and You'll be tired after reading this long stuff.. blah blah... " />

    <TextView
        android:id="@+id/rightTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toEndOf="@+id/leftTextView"
        android:layout_toRightOf="@+id/leftTextView"
        android:ellipsize="end"
        android:lines="1"
        android:text="Right Text" />

</RelativeLayout>

但是,解决方案的限制是您必须在 maxWidth 属性中提供固定值。因此,它会在不同的屏幕尺寸上显示不同的外观。不过,在大多数情况下,您不会遇到问题。

另外,在单行中显示长 textView android:ellipsize="marquee" 是一个不错的选择。因为它会水平滚动您的视图。但不要忘记在您的代码中写下这个textView.setSelected(true) 以使其工作。 Detail

【讨论】:

  • Android 的屏幕尺寸差异如此之大(加上纵向和横向),固定宽度绝对不是理想的方法。
  • 我已经说过,当您知道某个固定宽度的视图大小时,这将起作用。否则,您可以按照@whizzle 的建议以编程方式进行。
【解决方案3】:

我认为您需要进行自定义布局。这适用于我制作的示例,它满足您在上面发布的所有要求,但是您需要在代码中添加更多的数学知识以考虑 layout_margins 和 padding。

这里发生的事情的基本思想是我继承了 LinearLayout 并且在 onMeasure 过程中,我检查以确保正确的视图可以选择占用尽可能多的空间。请注意,我必须重新测量正确的视图,而不仅仅是获得测量的宽度,因为线性布局不会给它足够的空间。一旦你有正确的视图占用了多少空间,检查中间的视图(称为 leftView...sorry)是否占用了比你想要的更多的空间。如果是这样,只需给它剩余的空间。

根据您对它在 RecyclerView 中的要求...我知道您说过您想要一个纯 xml 解决方案,但是如果您在代码中将其处理为 xml 1. 可能会获得更好的性能。 2. 将需要更多的计算,而不是直接自己做。

public class CustomLinearLayout extends LinearLayout {

private View child0;
private TextView leftView, rightView;
public CustomLinearLayout(Context context) {
    super(context);
}

public CustomLinearLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    if (rightView == null) {
        child0 = getChildAt(0);
        leftView = (TextView)getChildAt(1);
        rightView = (TextView) getChildAt(2);
    }

    int spec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
    rightView.measure(spec, spec);

    int remaining = getMeasuredWidth() - child0.getMeasuredWidth() - rightView.getMeasuredWidth();
    if (leftView.getMeasuredWidth() > remaining) {
        int specW = MeasureSpec.makeMeasureSpec(remaining, MeasureSpec.AT_MOST);
        int specH = MeasureSpec.makeMeasureSpec(leftView.getMeasuredHeight(), MeasureSpec.EXACTLY);
        leftView.measure(specW, specH);
    }
}

XML 布局

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.joshua.myapplication.MainActivity">

<com.example.joshua.myapplication.CustomLinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <ImageView
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:background="#FF0000"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxLines="1"
        android:textSize="18sp"
        android:text="My Left View With Really Really Long Text That should fill the screen"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:maxLines="1"
        android:textSize="18sp"
        android:text="My Right View"
        />
</com.example.joshua.myapplication.CustomLinearLayout>

<com.example.joshua.myapplication.CustomLinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:layout_marginTop="20dp">
    <ImageView
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:background="#FF0000"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxLines="1"
        android:textSize="18sp"
        android:text="My Left View with short text"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:maxLines="1"
        android:textSize="18sp"
        android:text="My Right View"
        />
</com.example.joshua.myapplication.CustomLinearLayout>
</LinearLayout>

【讨论】:

  • 感谢您的回答 - 我试了一下,效果很好,但 nshmura 的方法也有效,但纯粹是 XML,不依赖子类化。
【解决方案4】:

这是我的工作:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/fixedWidthImage"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:src="@drawable/ic_launcher_pro" />

    <TextView
        android:id="@+id/leftTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_gravity="center_vertical|left"
        android:ellipsize="marquee"
        android:lines="1"
        android:text="This is a very long text, and now even longer" />

    <TextView
        android:id="@+id/rightTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|left"
        android:lines="1"
        android:text="This is also quite long" />

</LinearLayout>

android:layout_weight="1" 在这里起到了“把戏”的作用。但是,文档对此并不十分清楚:

例如,如果有三个文本字段,其中两个声明一个 权重为 1,而另一个没有权重,第三个文本字段 没有重量不会增长,只会占据所需的面积 它的内容。

(https://developer.android.com/guide/topics/ui/layout/linear.html#Weight)

没有详细说明没有空间可填充但没有足够空间容纳所有视图的情况。对上述文档的一种解释是,没有权重的字段(在本例中为 rightTextView)将占据其内容所需的区域,而具有权重的字段(在本例中为 leftTextView)将“增长”(如否定增长),这正是发生的事情。

【讨论】:

  • 虽然权重允许您提到的“负增长”,但它也会在不需要时扩展字段以填充宽度。这最终导致rightTextView 被固定到父视图的右侧/末端。从功能上讲,它与我在问题中尝试的 #2 中的表现相同。
  • @Emanuel Moecklin 如果我使用的是相对布局而不是线性布局怎么办?
  • @Stonz2 这也是我的测试结果
猜你喜欢
  • 1970-01-01
  • 2021-11-13
  • 2022-01-23
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 2012-08-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多