LinearLayout:防止最后 child 被前面的大文本视图推出或挤压

LinearLayout: prevent last child from getting pushed out or squeezed by large textview before it

我有一个LinearLayout,里面有两个children。第一个是带有动态内容的 TextView,第二个是一个按钮。我的问题是按钮被推出 parent 或被挤压到不再可见的程度。我希望 TextView 认识到它的 parent 中没有更多的 space 和第二个 child,并开始一个新行而不是窃取 space 需要第二个 child。但是,按钮应该位于文本旁边,而不是默认情况下一直位于右侧。

我尝试了很多不同的方法,但都没有用,在下面的代码中,我只是发布了我想要工作的最小示例,没有我已经尝试过的不同更改。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="sdrndesfntzrfndtzmufzksbnsfdn stnbhdsfbns sth st ömcfz,frznz"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />
</LinearLayout>

所以总而言之:我希望 TextView 占用几行而不是占用 Button 的 space。行数当然应该是动态的,具体取决于视图中的文本。 Button 应该紧挨着 textview 并随着文本变大而向右移动。

这是我想要的视觉表示:

这是我得到的。

设置文本视图的 maxwidth 是一个简单的解决方案,但在更复杂和动态的布局中,您并不总是知道最大宽度是多少。所以最好有一个没有 hard-coded maxWidths 的解决方案。

您可以将 TextView 和 Button 的宽度设置为 0dp 并设置权重,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="3"
        android:text="sdrndesfntzrfndtzmufzksbnsfdn stnbhdsfbns sth st ömcfz,frznz"/>
    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Button" />
</LinearLayout>

在此示例中,TextViews 宽度为 3/4s,Buttons 宽度为 Parent 宽度的 1/4,但您可以通过调整权重将其设置为任何您想要的值。

使用 RelativeLayout 以获得更好的结果

<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toStartOf="@id/btn"
            android:layout_marginEnd="5dp"
            android:text="sdrndesfntzrfndtzmufzksbnsfdn stnbhdsfbns sth st ömcfz,frznz"/>
    
        <Button
            android:id="@+id/btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:text="Button" />
    </RelativeLayout>

你可以试试FlexboxLayouthttps://github.com/google/flexbox-layout

<com.google.android.flexbox.FlexboxLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:alignItems="center"
    app:alignContent="center"
    app:flexDirection="row"
    app:flexWrap="nowrap">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="sdrndesfntzrfndtzmufzksbnsfdn stnbhdsfbns sth st ömcfz,frznz dfgsfsdfsdf"
        app:layout_flexShrink="10000"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"/>
</com.google.android.flexbox.FlexboxLayout>

app:layout_flexShrink="10000" 是正确调整元素大小的方法。

EDT build.gradle 配置:

allprojects {
  repositories {
    ...
    maven { url "https://maven.google.com" }
  }
}

dependencies {
  ...
  implementation 'com.google.android.flexbox:flexbox:3.0.0'
}

在布局中进行

这可以使用 ConstraintLayout 解决:

  • packed横链
  • 0 水平偏差。
  • 启用约束宽度
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="sdrndesfntzrfndtzmufzksbnsfdn stnbhdsfbns sth st ömcfz,frznz"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/button"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/textView"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

动态执行

如果您仍然需要使用 LinearLayout,那么您可以通过编程方式进行。由于您需要 wrap_content TextViewButton 的宽度相同,因此从逻辑上讲这是无法实现的,因为当宽度之和大于屏幕宽度时,某些视图将会贪心。

因此你决定这样做 wrap_content 直到按钮在不超出屏幕末端的情况下环绕其宽度。

但是现在 TextView 宽度不应该是 wrap_content;相反,它应该是一些固定大小;因为如果它仍然 wrap_content 它会在 Button 上贪婪,然后将它踢出屏幕或像你的情况一样被挤压。

因此,我们需要以编程方式做一些努力来了解屏幕宽度,因此我们将 TextView 限制为等式:

TextView_maxWidth =  screenWidth - buttonWidth

解决方案 1:使用 LinearLayout

如果我们在布局上设置 TextView 文本,现在按钮将被挤压,我们无法以编程方式确定按钮的 wrap_content 大小,因此在此解决方案中,textView在我们获得按钮大小后以编程方式设置文本。

布局(没什么花哨的):

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

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />
</LinearLayout>

行为:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    LinearLayout root = findViewById(R.id.root);
    
    root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                root.getViewTreeObserver()
                        .removeOnGlobalLayoutListener(this);
            }
            int width = root.getWidth();
            Button button = findViewById(R.id.button);
            int buttonWidth = button.getWidth();
            int maxTextWidth = width - buttonWidth;

            TextView textView = findViewById(R.id.textView);
            textView.setMaxWidth(maxTextWidth);
            textView.setText("drndesfntzrfndtzmufzksbnsfdn stnbhdsfbns sth st ömcfz,frznz");

        }
    });
}

解决方案 2:使用 ConstraintLayout

LinearLayout不同,ConstraintLayout可以强制按钮大小为wrap_content而不被挤压,因此我们可以在布局上设置TextView的文本。

布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="sdrn desf ntzrf ndtz mufzk sbnsf dn sdrnde sf ntzrfn dtz mufzks bns fdn sd rn de sfnt zrf ndtzmufzk sbnsfdnstn bhdsfbns sth st ömcfz, frznz"
        app:layout_constrainedWidth="true"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintStart_toEndOf="@id/textView"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

行为:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ConstraintLayout root = findViewById(R.id.root);
    root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                root.getViewTreeObserver()
                        .removeOnGlobalLayoutListener(this);
            }
            
            int width = root.getWidth();
            Button button = findViewById(R.id.button);
            int buttonWidth = button.getWidth();
            int maxTextWidth = width - buttonWidth;
            
            TextView textView = findViewById(R.id.textView);
            textView.setMaxWidth(maxTextWidth); 

        }
    });
}

预览: