ConstraintLayout链和文本省略号+右侧的图像 [英] ConstraintLayout Chains and Text Ellipsis + Image on the Right

查看:127
本文介绍了ConstraintLayout链和文本省略号+右侧的图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的答案中添加了信息,以更详细地解释constrainedWidth/Height的用途/用途以及何时使用它们.

Added information in the answer below to explain in more detail why/what does constrainedWidth/Height do and when it's applicable to use them.

如果使用的是ConstraintLayout 1.1.0,则要使用的正确属性是app:layout_constrainedWidth="true"来代替旧的app:layout_constraintWidth_default="wrap"(以及高度对应).查看最新答案.

If you are using ConstraintLayout 1.1.0, the correct property to use is app:layout_constrainedWidth="true" in place of the old app:layout_constraintWidth_default="wrap" (and the height counterpart). See updated answer.

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

If you are using ConstraintLayout 1.0.0 stable (or above) (1.0.2 at this time), see the updated Answer for a simpler solution without the need to nest layouts.

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

Using ConstraintLayouts-Beta3 released on Nov 3rd 2016. (source)

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

I'm trying to do the following:

|                                        |
|<-[TextView]<->[ImageView] -----------> |
|                                        |

我通过这样的布局实现了这一点:

Which I have achieved with a layout like so:

  <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"/>

看起来不错,但是当文本的长度超过可用空间时……

This looks ok, but when the text is longer than the available space…

|                                        |
|<-[TextView Larger Than The Space Avail]|
|                                        |

文本视图具有指定以下内容的样式:

The text view has a style that specifies these:

<item name="android:lines">1</item>
<item name="android:maxLines">1</item>
<item name="android:ellipsize">end</item>

所以应该有效,但是我不确定在向右滑动图像然后在此处停止并让文本视图能够理解之前需要使图像滑动什么约束没有更多空间了.

So it should work, but I'm not sure what constraints I need to have the image slide until the right and then stop there and let the text view understand there's no more space.

我想念什么?

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

Note: If I set the textview's width to the 0dp, it works, but then the image is always on the right (horizontal Bias seems to be ignored for it)

注意2:我也尝试过使用beta2,实际上,看来Beta3具有

Note2: I have tried this with beta2 as well, in fact, it seems like Beta3 has a bug in the visual editor.

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

UPDATE: I tried to replicate this in Xcode/AutoLayout:

这是带有短文字的外观

现在布局相同,我只需要在文本视图中输入一个长文本即可.

Now the same layout, I just type a long text in the text view…

如您所见,图像视图的轨迹(右侧)约束说:您距右侧边距 8个或更多点.

As you can see the trail (right) constraint for the image view says: you're 8 or more points from the right margin.

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

It's also pinned to the left to the label (textView).

根据我从Twitter刚学到的信息,目前 可能无法在Android的ConstraintLayout上实现:来源

From what I have just learned from Twitter, this may not be possible on Android's ConstraintLayout at the moment: Source

推荐答案

2020年7月更新:constrainedWidth/Height有什么作用?

很多人一直问我constrainedWidth/Height在设置为true时(默认为false)到底是做什么的. 我终于有了一个答案(来自Google员工),所以我清除了所有收集到的疑问,这是我收集的内容(有些是我的话,有些是直接引号

UPDATE JULY 2020: What does constrainedWidth/Height do?

A lot of people kept asking me what exactly does this constrainedWidth/Height do when set to true (defaults to false). I finally have an answer (from a Google employee), so in lieu of clearing up all the doubts people coming to this post keep having, here's what I gathered (some are my words, some are direct quotes from the original Google issue quote.

ConstraintLayout需要确定涉及的每个视图的尺寸,并且根据该视图受约束的方式,它必须执行不同的计算.

ConstraintLayout needs to determine the dimension of every view involved, and depending on how said view is constrained, it has to perform different calculations.

给出一个视图:

  1. 如果它是固定尺寸,CL将仅使用该尺寸.
  2. 如果是match_parent,CL将使用父级的确切尺寸
  3. 如果是wrap_content,CL会询问窗口小部件的大小,然后将其用作固定尺寸
  4. 如果为0dp,则CL会将约束应用于尺寸
  1. if it's a fixed dimension, CL will just use that dimension.
  2. if it's match_parent, CL will use the exact dimension of parent
  3. if it's wrap_content, CL will ask the widget for its size, but then use it as a fixed dimension
  4. if it's 0dp, CL will apply constraints to the dimension

1)固定尺寸

这是一个宽度/高度固定的视图,例如24dp.在这种情况下,CL将仅使用该值,而在大小调整方面不需要该小部件的其他计算.

1) Fixed Dimension

This is a view whose width/height are fixed, say 24dp. In this case, CL will simply use that value, no other calculation needed for that widget in regards of sizing.

我一直认为这对于CL无效,但是事实证明它的行为与以前的版本相同,它抓住了父对象的尺寸并将其用作固定"的.与上面的#1不同,我认为这可能会在计算上更加昂贵,因为CL现在需要确保已知父维度可以在此处使用它们.我没有这方面的证据,也没有很多经验,因为我一直认为这不是真的有效,所以从不使用它.

I always thought this was not valid for CL, but turns out that it behaves like it used to in previous versions, it grabs the dimensions of the parent and uses that as "fixed". Unlike #1 above, I assume this may be more computationally expensive since CL now needs to ensure the parent dimensions are known to be able to use them here. I don't have proof of this nor a lot of experience, since I always thought this wasn't really valid so never used it.

如预期的那样,视图必须确定其所需大小",因此,如果说是ImageView,它将根据其来源向imageView询问尺寸.获得上述数字后,就可以像#1一样用作固定大小.

As expected, the view has to determine its "required size", so if it's say an ImageView it will ask the imageView for its dimensions based on its source. After said number is obtained, it's used as a Fixed Size, like #1.

这是CL的亮点,方法是对每个维度(宽度和高度)应用约束,并根据算法的结果确定维度的值.

This is where CL shines, by applying the constrains to each dimension (width, and height), and letting the dimension's value be determined by the outcome of the algorithm.

首先要了解的是,0dp具有传播和包裹行为(和百分比);为了 wrap ,引擎从视图的wrap_content(上面的#3)的尺寸开始,但是在需要时等待约束 change .假设您使用 wrap 作为文本视图的宽度,它的约束条件将其固定在屏幕的边缘(开始/结束到父视图). 这些可能会朝不同的方向拉动;文本视图可能会希望小些以包装文本,并且约束将小部件的边缘以到达父级起点/终点.这里有一场战斗. (如果文字比空格,则战斗仍然存在,但方向相反).

The first thing to understand is that 0dp has a spread and wrap behavior (and percent); in order to wrap, the engine starts with the dimension of the view's wrap_content (#3 above) but waits for constrains to change it if/when needed. Say you use wrap for the width of a text view, and its constrains pin it to the edges of the screen (start/end to parent). Those can be pulling in different directions; the text view will likely want to be small to wrap the text and the constrains will pull the edges of the widget to reach the parent start/end. There's a battle here. (if the text is larger than the space, the battle still exists, but in the opposite direction).

之所以存在此属性,是因为某些小部件(_Like textView)带有一些快捷方式,并且当存在0dp时,它们可能并不总是正确地更新.重要的是要注意,具有0dp +权重的LinearLayouts做的是同一件事(因此为什么也是LL的问题);通过使用constrainedWidth/Height,像TextView这样的小部件可以在需要时正确地将0dp与 wrapping 行为一起使用;它为视图提供了正确重新测量自身的机会.

The reason why this attribute exists, is because some widgets (_Like textView), take some shortcuts and when there's a 0dp, they may not always correctly update. It's important to note that LinearLayouts with 0dp + weights did the same thing (hence why this was an issue with LL too); by using constrainedWidth/Height, a widget like a TextView can correctly use 0dp with wrapping behavior when needed; it gives the view a chance to correctly remeasure itself.

当您重复使用TexViews时,这个问题通常会显现出来(我不知道确切地从哪个 other 视图中受益,但是我认为所有带有文本的内容都容易进行计算快捷键/hacks) ,并且可能需要这些额外的信息才能正确触发重新测量).最需要在诸如TextView之类的文本上重用Widget,考虑一下RecyclerView,其中ViewHolder位于ConstraintLayout(非常常见)中,当您滚动时,ViewHolder被重用并重新绑定到另一个数据模型" ;并且如果没有此属性,则TextView将/可能无法为可能出现的 new 文本重新计算其大小.

This problem mostly manifests when you reuse TexViews (I don't know exactly which other views benefit from this, but I assume anything that has text is prone to have calculation shortcuts/hacks and may need this extra bit of info to correctly trigger a remeasure). Reusing a Widget with Text like a TextView, is where this is mostly needed, think of a RecyclerView where your ViewHolder is in a ConstraintLayout (quite common), when you scroll, the ViewHolder is reused and re-bound to another "data model" and without this attribute, the TextView will/may fail to recalculate its size for the new text that may be coming.

我希望这是有道理的.

tl;dr:这是一种解决方法,可以解决某些小部件在重用时无法重新计算其尺寸的潜在问题,特别是在RecyclerView中,但很可能不限于此.

tl;dr: it's a workaround to fix potential issues with some widgets that fail to recompute their dimensions when reused, notably in a RecyclerView, but most likely not limited to it.

那里有. :)

如果您使用的是ConstraintLayout 1.1.0,则要使用的正确属性是app:layout_constrainedWidth="true"来代替旧的app:layout_constraintWidth_default="wrap"(以及高度对应的对象)

If you are using ConstraintLayout 1.1.0, the correct property to use is app:layout_constrainedWidth="true" in place of the old app:layout_constraintWidth_default="wrap" (and the height counterpart)

我正在使用约束布局1.0.2,并且使用app:layout_constraintWidth_default="wrap"(在1.0.0中引入了该属性,但本文所使用的Beta没有该属性)发现了嵌套较少的解决方案.

I’m using Constraint Layouts 1.0.2 and I have found a less nested solution using app:layout_constraintWidth_default="wrap" (a property that got introduced in 1.0.0 but the Beta this post was using didn’t have).

现在,您可以删除所有内容并以这种方式代替包含LinearLayoutFrameLayout:

Instead of the FrameLayout that contains a LinearLayout you can now remove all that and have it this way:

    <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>

这有效地实现了我想要的功能,没有黑客或指导方针或硬编码的大小.

This effectively does exactly what I want, without hacks or guidelines or hardcoded sizes.

TextView将使用约束"提供的大小(在正常情况下,这将意味着它是错误的,或者会超出父"的大小),但是由于有了新的属性,这些约束才可以弯曲/如果内容较小/较大,则损坏.

The TextView will use the size provided by the Constraints (which under normal circumstances would mean it would either be wrong or will grow beyond the ‘parent’), but thanks to the new attribute, those constraints are allowed to be bent/broken if the content is smaller/larger.

我不得不说它比iOS优先级要好得多. (至少对我来说要容易得多).对此Google表示赞赏:)

I have to say it works much better than iOS Priorities. (At least it’s a lot easier to grasp to me). Thumbs up for Google on this one :)

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

Based upon Nicolas Roard's answer, I was going to create a custom container that would basically calculate the available space, and programmatically set the maxWidth on the TextView. Instead of adding another class, unit test, possible set of bugs, etc., to the project, I tried a slightly less efficient method of nesting a couple of layouts; considering we've been nesting layouts since the age of dawn and that this is not going to be on any scrolling list view or moving too much (or at all) and that I am using ConstraintLayouts to flatten most of the hierarchy (like never before!), then I don't think a little nesting until this is better supported is that bad.

所以我所做的基本上是使用一个FrameLayout,该布局经过设计优化(或认为)有一个孩子(可以容纳更多孩子).此FrameLayout是应用了ConstraintLayout规则的框架,如下所示:

So what I did was basically, use a FrameLayout, which is by design optimized (or thought) to have one child (tho it can contain more). This FrameLayout is the one that has the ConstraintLayout rules applied like so:

  <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>

因此,在我的 real 应用程序中,此FrameLayout位于另一个ConstraintLayout内,该ConstraintLayout的左侧有一个图标和一些其他内容,但是对于此示例,假设您必须固定"图钉.此FrameLayout的左侧/右侧到您要占用的任何空间.在此示例中,您可以看到我在所有约束中都使用了parent,但是此FrameLayout的左侧和右侧可能还有其他小部件.感谢ConstraintLayout的魔力,它将占据所有可用空间.

So in my real app, this FrameLayout is inside another ConstraintLayout that has an icon to its left and some other stuff, but for the sake of this example, imagine you have to "pin" the left/right of this FrameLayout to whatever space you want to occupy. In this example you can see I'm using parent in all constraints, but there could be other widgets left and right of this FrameLayout; thanks to ConstraintLayout's magic, this will occupy all that available space.

现在这是技巧的第二部分……因为ConstraintLayout保证FrameLayout将使用所有空间",我们拥有的(再也没有(或更少)),现在我可以在内部使用LinearLayout……就像这样……

Now here comes the 2nd part of the trick… since ConstraintLayout guarantees that the FrameLayout will use "all the space" we have and never more (or less), I can now use a LinearLayout inside… like so…

     <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>

精明的读者会注意到,LinearLayout的宽度为wrap_content,这对于确保子TextView的宽度为0dp和weight为1非常重要,这意味着它将免费使用所有其他所有小部件都计算出宽度后的空格.

Astute readers will notice that the LinearLayout has wrap_content in its width, that's very important for then the child TextView can have a width of 0dp and a weight of 1, meaning it will take all available free space after all the other widgets have calculated their width.

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

In this particular case the other child (ImageView) caret has no weight specified and a fixed width, therefore the TextView doesn't have to share/split the free space with anybody else and it can take it all (but only free space, remember its width is 0dp).

这种效率较低的方法可以有效地实现我想要的效果,即使您愿意,也可以使用更少的ConstraintLayout Magic .

This less efficient approach, effectively achieves exactly what I wanted, albeit with less ConstraintLayout Magic if you will.

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

On the plus side, I didn't have to create a custom view, perform math and issue a requestLayout() after all my math was done; this less efficient approach will/should scale and until ConstraintLayout offers a valid alternative, it may be enough as it is.

向Google工程师大喊大叫,他们在社交媒体上做出了回应,并最终花了一些时间对此进行思考.也许将来,当他们编写有关ConstraintLayout 1.1的任务和故事要点时,他们会记住这一点并提出一个好的解决方案

这篇关于ConstraintLayout链和文本省略号+右侧的图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆