ConstraintLayout链和文本省略+右侧图像

Mar*_*ini 31 android android-studio android-constraintlayout constraint-layout-chains

2018年7月更新:

如果您正在使用ConstraintLayout 1.1.0,则使用正确的属性app:layout_constrainedWidth="true"代替旧的app:layout_constraintWidth_default="wrap"(和高度对应的).查看更新的答案.

2017年11月更新:

如果您使用的是ConstraintLayout 1.0.0稳定版(或以上版本)(此时为1.0.2版),请参阅更新的答案以获得更简单的解决方案,而无需嵌套布局.

原始问题:

使用ConstraintLayouts-Beta3于2016年11月3日发布.(来源)

我正在尝试执行以下操作:

ConstraintLayout 1.1.0

我用这样的布局实现了这个目标:

|                                        |
|<-[TextView]<->[ImageView] -----------> |
|                                        |
Run Code Online (Sandbox Code Playgroud)

这看起来不错,但是当文本比可用空间长时......

app:layout_constrainedWidth="true" 文本视图具有指定以下内容的样式:

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

      app:layout_constraintHorizontal_chainStyle="packed"

      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      app:layout_constraintRight_toLeftOf="@+id/caret"
      app:layout_constraintHorizontal_bias="0.0"

      android:text="Some Text"
      android:textAlignment="viewStart"
      android:gravity="start" />

  <ImageView
      android:id="@+id/caret"
      android:layout_width="wrap_content"
      android:layout_height="8dp"
      app:layout_constraintDimensionRatio="1:1"

      app:layout_constraintLeft_toRightOf="@+id/textView"
      app:layout_constraintRight_toRightOf="parent"

      app:layout_constraintTop_toTopOf="@+id/textView"
      app:layout_constraintBottom_toBottomOf="@+id/textView"


      app:layout_constraintHorizontal_bias="0.0"

      android:contentDescription=""
      app:srcCompat="@drawable/ic_selection"
      android:layout_marginStart="8dp"/>
Run Code Online (Sandbox Code Playgroud)

所以它应该工作,但我不确定我需要什么约束让图像滑到右边然后在那里让文本视图理解没有更多的空间.

我错过了什么?

注意:如果我将textview的宽度设置为0dp,它可以工作,但是图像总是在右边(水平偏差似乎被忽略了)

注2:我也尝试过beta2,事实上,似乎Beta3 在可视化编辑器中有一个错误.

更新:我试图在Xcode/AutoLayout中复制它:

这是短文本的外观

短文

现在是相同的布局,我只需在文本视图中键入一个长文本...

长文

正如您可以看到图像视图的轨迹(右)约束所示:您从右边距开始有8个或更多点.

它也固定在标签的左侧(textView).

从我刚刚从Twitter上学到的东西,目前在Android的ConstraintLayout上可能无法做到这一点:来源

Mar*_*ini 41

2018年7月更新:

如果您正在使用ConstraintLayout 1.1.0,则使用正确的属性app:layout_constrainedWidth="true"代替旧的app:layout_constraintWidth_default="wrap"(和高度对应的)

2017年11月更新

我正在使用Constraint Layouts 1.0.2并且我发现了一个较少嵌套的解决方案app:layout_constraintWidth_default="wrap"(在1.0.0中引入了一个属性,但是这篇文章使用的Beta没有).

而不是FrameLayout包含a,LinearLayout你现在可以删除所有这些,并以这种方式:

    <android.support.constraint.ConstraintLayout
      android:id="@+id/new_way_container"
      android:layout_height="wrap_content"
      android:layout_width="0dp" // THIS GUY USES ALL THE WIDTH.
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent">

      <TextView
        android:ellipsize="end"
        android:id="@+id/some_text"
        android:layout_height="wrap_content"
        android:layout_width="0dp" //NO WRAP CONTENT, USE CONSTRAINTS
        android:lines="1"
        android:maxLines="1"
        app:layout_constraintEnd_toStartOf="@+id/disclosure_arrow"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintHorizontal_chainStyle="packed" //CHAIN IT for biasing.
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_default="wrap" /> //THIS IS THE KEY THAT WILL CAUSE THIS TO WORK

      <ImageView
        android:id="@+id/disclosure_arrow"
        android:layout_height="wrap_content"
        android:layout_width="10dp"
        app:layout_constraintBottom_toTopOf="@id/some_text"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/some_text"
        app:layout_constraintTop_toBottomOf="@id/some_text"
        app:srcCompat="@drawable/your_vector_image" />
    </android.support.constraint.ConstraintLayout>
Run Code Online (Sandbox Code Playgroud)

这有效地完成了我想要的,没有黑客或指南或硬编码的大小.

TextView将使用Constraints提供的大小(在正常情况下它意味着它会错误或将超出'parent'),但是由于new属性,这些约束允许弯曲/破坏,如果内容越来越小.

我不得不说它比iOS优先级要好得多.(至少对我来说要容易得多).谷歌在这一个竖起大拇指:)

老答案(如果你仍然需要它).

基于Nicolas Roard的回答,我打算创建一个基本上计算可用空间的自定义容器,并以编程方式在TextView上设置maxWidth.我没有在项目中添加另一个类,单元测试,可能的错误集等,而是尝试了一种嵌套几个布局的效率稍低的方法; 考虑到自从黎明时代以来我们一直在嵌套布局,并且这不会出现在任何滚动列表视图或移动太多(或根本没有)并且我使用ConstraintLayouts来压缩大部分层次结构(从未像现在这样) !),然后我不认为有一点嵌套,直到这个更好的支持是坏的.

所以我所做的基本上是使用FrameLayout,它是通过设计优化(或思考)来生成一个孩子(因为它可以包含更多).这个FrameLayout是应用了ConstraintLayout规则的那样:

  <FrameLayout
      android:id="@+id/hostTextWithCaretContainer"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      app:layout_constraintRight_toRightOf="parent">

      <!-- MY CONTENT GOES HERE -->

  </FrameLayout>
Run Code Online (Sandbox Code Playgroud)

所以在我的真实应用程序中,这个FrameLayout位于另一个ConstraintLayout内部,左边有一个图标和其他一些东西,但是为了这个例子,想象你必须将这个FrameLayout的左/右"固定"到你的任何空间想要占领.在这个例子中,你可以看到我parent在所有约束中使用,但是这个FrameLayout左右可能有其他小部件; 感谢ConstraintLayout的魔力,这将占据所有可用空间.

现在来看这个技巧的第二部分......因为ConstraintLayout保证FrameLayout将使用我们拥有的"所有空间"而且永远不会更多(或更少),我现在可以在里面使用LinearLayout ...就像这样......

     <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

      <TextView
          android:id="@+id/textView"
          android:layout_height="wrap_content"
          android:layout_width="0dp"
          tools:text="Some Text"
          android:text="Some Text"
          android:textAlignment="viewStart"
          android:layout_gravity="center_vertical"
          android:gravity="start"
          android:ellipsize="end"
          android:maxLines="1"
          android:layout_weight="1"/>

      <ImageView
          android:id="@+id/caret"
          android:layout_width="8dp"
          android:layout_height="8dp"
          app:srcCompat="@drawable/ic_selection"
          android:contentDescription=""
          android:layout_gravity="center_vertical"
          android:layout_marginStart="8dp"
          android:layout_marginEnd="8dp" />

    </LinearLayout>
Run Code Online (Sandbox Code Playgroud)

精明的读者会注意到LinearLayout wrap_content的宽度非常重要,因为子TextView的宽度为0dp,宽度weight为1,这意味着在所有其他小部件计算出宽度后,它将占用所有可用空间.

在这种特殊情况下,另一个子(ImageView)caret没有指定权重和固定宽度,因此TextView不必与任何其他人共享/拆分自由空间,它可以全部使用(但只有自由空间,请记住它宽度为0dp).

这种效率较低的方法,有效地实现了我想要的,尽管如果你愿意的话,ConstraintLayout Magic会更少.

从好的方面来说,我不需要创建自定义视图,执行数学并在requestLayout()完成所有数学操作后发出一个; 这种效率较低的方法将会/应该扩展,直到ConstraintLayout提供有效的替代方案,它可能就足够了.

向那些在社交媒体上回复并最终花时间思考这个问题的Google工程师致敬.也许在将来,当他们编写有关ConstraintLayout 1.1的任务和故事点时,他们会记住这一点并提出一个很好的解决方案