【问题标题】:Expand TextView with wrap_content until the neighbor view reaches the end of the parent使用 wrap_content 展开 TextView 直到邻居视图到达父视图的末尾
【发布时间】:2014-07-29 04:52:01
【问题描述】:

我需要实现如下布局:

我在相对布局中有两个 TextView:绿色的一个是带有wrap_content 的固定文本,黑色的一个是带有wrap_content 的动态文本。黑色文本可以更改并变得很长。我希望黑色 TextView 与文本一起扩展,直到绿色视图到达父级的末尾。如果发生这种情况,黑色的 TextView 应该停止扩展并椭圆化结束。

我怎样才能做到这一点?

我尝试了什么:

 <RelativeLayout
    android:id="@+id/parent"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >


    <TextView
        android:id="@+id/leftTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:maxLines="1"
        android:layout_alignParentLeft="true"
        android:textSize="18sp" />

    <TextView
        android:id="@+id/rightTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/leftTextView"
        android:textSize="18sp" />

</RelativeLayout>

但是当黑色文本变得越来越大时,它会将绿色文本推出视图

【问题讨论】:

    标签: android textview android-relativelayout


    【解决方案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="0">
    
            <TableRow
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:gravity="center_vertical">
    
                <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:padding="4dp"
                        android:maxLines="1"
                        android:ellipsize="end"
                        android:text="abcdefghijklmnopqrstuvwxyz"/>
    
                <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="0">
    
            <TableRow
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:gravity="center_vertical">
    
                <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:padding="4dp"
                        android:maxLines="1"
                        android:ellipsize="end"
                        android:text="Longer Text view abcdefghijklmnopqrstuvwxyz"/>
    
                <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="0">
    
            <TableRow
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:gravity="center_vertical">
    
                <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:padding="4dp"
                        android:maxLines="1"
                        android:ellipsize="end"
                        android:text="Text view that is very logn and will not fit the parent width abcdefghijklmnopqrstuvwxyz"/>
    
                <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>
    

    Here 是同一个问题 ;)

    【讨论】:

    • 这工作正常。从未使用过 TableLayout,但这次它看起来像是救世主。
    【解决方案2】:

    ConstraintLayout 解决方案来了。

    魔术是Chains

    <?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="match_parent"
        android:layout_height="wrap_content"
        android:padding="20dp">
    
        <TextView
            android:id="@+id/leftTv"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:maxLines="1"
            android:textColor="#333333"
            android:textSize="18sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/rightTv"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintHorizontal_chainStyle="packed"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintWidth_default="wrap"
            tools:text="Text view that is very long and will not fit the" />
    
        <TextView
            android:id="@+id/rightTv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginLeft="16dp"
            android:textColor="#21b38a"
            android:textSize="16sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/leftTv"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="Text View" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    【讨论】:

    • 当你的rightTv 太长时,leftTv 消失,什么都不显示
    • 谢谢。这就是我要找的。我认为这应该是正确的答案。因为rightTv的关注时间太长了,我觉得这样是不可能的,我们需要改一下设计。就我而言,确定了正确的文本(右视图)宽度。
    • 非常感谢。 app:layout_constraintWidth_default="wrap" 对我有用。我什至尝试过链,但不知道存在约束宽度。
    • 你好,5小时后我找到了你的答案。
    • 你好,当leftTv长时,它的字符串不会从头显示。为什么会有对齐问题?谢谢
    【解决方案3】:

    我建议将两个TextView 包装成LinearLayout。然后将android:weightSum="1" 应用于此LinearLayout 并将android:layout_weight="1" 应用于必须扩展的子TextView

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:weightSum="1">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ellipsize="end"
            android:maxLines="1"
            android:padding="8dp"
            android:text="blabla bla bla bla bla bla bla bla bla bla bla bla bla "/>
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="8dp"
            android:text="static text"/>
    
    </LinearLayout>
    

    记得设置这两个属性才能完美工作:

    android:ellipsize="end"
    android:maxLines="1"
    

    LinearLayout 必须有android:layout_width="wrap_content"

    如果您希望这个 ViewGroup 占据整个空间,请用另一个 ViewGroup 包裹它:

    <RelativeLayout
       android:layout_height="wrap_content"
       android:layout_width="match_parent">
    
       <!--The previous view group-->
    
    </RelativeLayout>
    

    【讨论】:

      【解决方案4】:

      这里有一个布局,可以做你想做的事情:

      <RelativeLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:gravity="left">
      
          <TextView
          android:id="@+id/leftTextView"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_toLefOf="@+id/rightTextView"
          android:maxLines="1"
          android:textSize="18sp" />
      
          <TextView
          android:id="@+id/rightTextView"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignParentRight="true"
          android:textSize="18sp" />
      
      </RelativeLayout>
      

      这里的关键部分是相对布局的重力,以及将右侧 textview 对齐为 alignParentRight ,左侧 textview 附加到左侧。

      【讨论】:

      • 左侧的TextView在展开时只会与右侧的TextView重叠
      【解决方案5】:

      您所期望的布局可以在layout_weight attirbute 的帮助下创建,LinearLayout 附带。因此,您可能需要将LinearLayoutweightSumlayout_weight(传递给它的childview)属性一起使用。

      这是一个布局,它将您的布局宽度分为四个部分,在 Textview 之间分为 3:1。完整的右TextView 使左TextView 尽可能多地显示文本,而不会干扰右TextView

      请随时根据您的需要尝试使用变体weightSumlayout_weight 组合。

      布局:

      <LinearLayout
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:orientation="horizontal"
          android:weightSum="4" >
      
          <TextView
              android:layout_width="fill_parent"
              android:layout_height="wrap_content"
              android:layout_weight="1"
              android:singleLine="true"
              android:text="StackOverflow StackOverflow StackOverflow "
              />
      
          <TextView
              android:layout_width="fill_parent"
              android:layout_height="wrap_content"
              android:layout_gravity="right"
              android:layout_weight="3"
              android:maxLines="1"
              android:text="TextView"
              android:textColor="@android:color/white" />
      </LinearLayout>
      

      【讨论】:

      • 我试过你的代码,但你的第二个文本视图也占用了一些不需要的空间。就像我把一个 A 作为文本然后它占用 10 A 的空间
      • @IllegalArgument :正如您所说,您的第二个文本视图已修复。您可以在TextView 中尝试更多weightSumlayout_weight 的变体分布
      • 我也打算回答这个问题,但我还没有找到正确的答案,但只有在内容是饱和的情况下才使用变体
      • @IllegalArgument 我只是计算宽度并以编程方式设置左侧文本的最大宽度。你认为这是正确的方法吗?
      【解决方案6】:

      我设置了右文本视图宽度的左文本视图基础的最大宽度,看看我的代码。希望这会有所帮助。

      TextView leftText ;
      TextView rightText;
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
      
          leftText = (TextView) findViewById(R.id.leftTextView);
          rightText = (TextView) findViewById(R.id.rightTextView);
      
      
          measureView(leftText);
          measureView(rightText);
      
          leftText.setMaxWidth(getWidth() - rightText.getMeasuredWidth());
      
      }
      
      private void measureView(View view) {
          ViewGroup.LayoutParams params = view.getLayoutParams();
          int childWidth = ViewGroup.getChildMeasureSpec(0, view.getPaddingLeft() + view.getPaddingRight(), params.width);
          int childHeight = ViewGroup.getChildMeasureSpec(0, view.getPaddingBottom() + view.getPaddingTop(), params.height);
          view.measure(childWidth, childHeight);
      
      }
      
      private int getWidth() {
          WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
          Display display = wm.getDefaultDisplay();
          return display.getWidth();
      }
      

      xml 是:

      <LinearLayout
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="wrap_content">
      
      <TextView
          android:id="@+id/leftTextView"
          android:layout_width="wrap_content"
          android:layout_height="40dp"
          android:singleLine="true"
          android:text="abadabadabadabadabadabadabadabadabadabaasdfasdfasdfadabadabadabadabadabadabadabadabadabadabaasdfasdfasdfadabadabadabadabadabadabadabadabadabadabaasdfasdfasdfad"/>
      
      <TextView
          android:id="@+id/rightTextView"
          android:layout_width="wrap_content"
          android:layout_height="40dp"
          android:textColor="#adc391"
          android:singleLine="true"
          android:text="adsfasd"/>
      
      </LinearLayout>
      

      这是运行后的截图:

      【讨论】:

      • 我不确定这是正确的方法,但你能在 oncreate 本身中测量视图吗?我试图获取 textveiw 的行数,但我不得不使用 viewtreeobserver,因为 textview 的 requestlayout 和 measurelayout 功能不是这么称呼你的答案
      • 我可以在onCreate()中调用measureView()后得到测量的宽度
      【解决方案7】:

      我在我们的应用程序中遇到过这种用例。在我们的应用程序中,有 3 个视图。 ImageView | TextView | ImageView。两个 ImageView 必须在布局中可见。TextView 最后应该是椭圆形的。我想出了一个自定义的ViewGroup

      public class PriorityLayoutHorizontal extends ViewGroup
      {
      
          private ArrayList<Integer> mPriorityHighChildren;
      
          public PriorityLayoutHorizontal(Context context)
          {
              this(context, null);
          }
      
          public PriorityLayoutHorizontal(Context context, AttributeSet attrs)
          {
              this(context, attrs, 0);
          }
      
          public PriorityLayoutHorizontal(Context context, AttributeSet attrs, int defStyleAttr)
          {
              super(context, attrs, defStyleAttr);
      
              TypedArray typedArray = null;
              try
              {
                  typedArray = context.obtainStyledAttributes(attrs, R.styleable.PriorityLayoutHorizontal, defStyleAttr, 0);
                  final int id = typedArray.getResourceId(R.styleable.PriorityLayoutHorizontal_priorityHigh, -1);
                  if(id != -1)
                  {
                      final int[] highPriorityChildren = getResources().getIntArray(id);
                      setPriorityHigh(highPriorityChildren);
                  }
              }
              finally
              {
                  if(typedArray != null)
                  {
                      typedArray.recycle();
                  }
              }
          }
      
          public void setPriorityHigh(int... priorityHigh)
          {
              Integer[] priorityHighInteger = new Integer[priorityHigh.length];
              int i = 0;
              for(int value : priorityHigh)
              {
                  priorityHighInteger[i++] = Integer.valueOf(value);
              }
              mPriorityHighChildren = new ArrayList<Integer>(Arrays.asList(priorityHighInteger));
          }
      
          int mMaxHeight = 0;
      
          @Override
          protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
          {
              final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
              int widthUsed = 0;
              int heightUsed = 0;
              final int childCount = getChildCount();
      
              for(int childPosition : mPriorityHighChildren)
              {
                  final View childView = getChildAt(childPosition);
                  if(childView.getVisibility() != View.GONE)
                  {
                      measureChildWithMargins(childView, widthMeasureSpec, widthUsed, heightMeasureSpec, heightUsed);
                      widthUsed += getMeasuredWidthWithMargins(childView);
                      heightUsed = Math.max(getMeasuredHeightWithMargins(childView), heightUsed);
                  }
              }
      
              for(int childPosition = 0; childPosition < childCount; childPosition++)
              {
                  if(! mPriorityHighChildren.contains(Integer.valueOf(childPosition)))
                  {
                      final View childView = getChildAt(childPosition);
                      if(childView.getVisibility() != View.GONE)
                      {
                          measureChildWithMargins(childView, widthMeasureSpec, widthUsed, heightMeasureSpec, heightUsed);
                          widthUsed += getMeasuredWidthWithMargins(childView);
                          heightUsed = Math.max(getMeasuredHeightWithMargins(childView), heightUsed);
                      }
                  }
              }
      
              mMaxHeight = heightUsed;
      
              int heightSize = heightUsed + getPaddingTop() + getPaddingBottom();
              setMeasuredDimension(widthSize, heightSize);
          }
      
          @Override
          protected void onLayout(boolean changed, int l, int t, int r, int b)
          {
              final int paddingLeft = getPaddingLeft();
              final int paddingTop = getPaddingTop();
      
              int spaceUsed = paddingLeft;
              for (int childPosition = 0; childPosition < getChildCount(); childPosition++)
              {
                  final View childView = getChildAt(childPosition);
                  if(childView.getVisibility() != View.GONE)
                  {
                      final int top = (mMaxHeight / 2) - (childView.getMeasuredHeight() / 2);
                      layoutView(childView, spaceUsed, paddingTop + top, childView.getMeasuredWidth(), childView.getMeasuredHeight());
                      spaceUsed += getWidthWithMargins(childView);
                  }
              }
          }
      
          private int getWidthWithMargins(View child)
          {
              final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
              return child.getWidth() + lp.leftMargin + lp.rightMargin;
          }
      
          private int getHeightWithMargins(View child)
          {
              final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
              return child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
          }
      
          private int getMeasuredWidthWithMargins(View child)
          {
              final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
              return child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
          }
      
          private int getMeasuredHeightWithMargins(View child)
          {
              final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
              return child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
          }
      
          private void layoutView(View view, int left, int top, int width, int height)
          {
              MarginLayoutParams margins = (MarginLayoutParams) view.getLayoutParams();
              final int leftWithMargins = left + margins.leftMargin;
              final int topWithMargins = top + margins.topMargin;
      
              view.layout(leftWithMargins, topWithMargins, leftWithMargins + width, topWithMargins + height);
          }
      
          @Override
          public LayoutParams generateLayoutParams(AttributeSet attrs)
          {
              return new MarginLayoutParams(getContext(), attrs);
          }
      
          @Override
          protected LayoutParams generateDefaultLayoutParams()
          {
              return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
          }
      }
      

      在 values/attrs.xml 中声明一个自定义属性

      <declare-styleable name="PriorityLayoutHorizontal">
              <attr name="priorityHigh" format="reference"/>
      </declare-styleable>
      

      使用此布局,您可以将在布局中明确应该可见的视图赋予高优先级。剩余的一个TextView将根据屏幕剩余宽度绘制。

      要使用此布局:

          <com.example.component.PriorityLayoutHorizontal
                          android:layout_width="match_parent"
                          android:layout_height="wrap_content"
                          android:orientation="horizontal"
                          app:priorityHigh="@array/priority_array"
                          >
      
                          <TextView
                              android:id="@+id/contact_name"
                              android:layout_width="wrap_content"
                              android:layout_height="wrap_content"
                              android:singleLine="true"
                              />
      
                          <ImageView
                              android:layout_width="wrap_content"
                              android:layout_height="wrap_content"
                              android:src="@drawable/your_drawable"
                              />
      
      </com.example.component.PriorityLayoutHorizontal>
      

      并在values/arrays.xml中定义priority_array

      <integer-array name="priority_array">
              <item>1</item>
      </integer-array>
      

      在这里,我们提到了视图“1”的优先级。这是布局中的第二个 TextView。所以第二个 TextView 将始终可见,第一个 TextView 将被省略。

      P.S:这是一个通用的解决方案。即这可以与不同的视图一起使用,并且一行中的视图超过 2 个。您可以使用此布局,或者可以编写特定于您的用例的自定义 ViewGroup。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-24
        • 1970-01-01
        • 2021-08-06
        • 2021-09-23
        • 1970-01-01
        相关资源
        最近更新 更多