wake-up-neo.net

ConstraintLayout-Ketten und Textellipsen + Bild rechts

UPDATE JULI 2018:

Wenn Sie ConstraintLayout 1.1.0 verwenden, ist die richtige zu verwendende Eigenschaft app:layout_constrainedWidth="true" anstelle des alten app:layout_constraintWidth_default="wrap" (und des Gegenstücks zur Höhe). Siehe aktualisierte Antwort. 

UPDATE NOVEMBER 2017:

Wenn Sie ConstraintLayout 1.0.0 stable (oder höher) (1.0.2 zu diesem Zeitpunkt) verwenden, finden Sie in der aktualisierten Antwort eine einfachere Lösung, ohne dass Layouts verschachtelt werden müssen. 

Ursprüngliche Frage:

Using ConstraintLayouts-Beta3 wurde am 3. November 2016 veröffentlicht. ( source

Ich versuche folgendes zu tun:

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

Was ich mit so einem Layout erreicht habe:

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

Das sieht ok aus, aber wenn der Text länger ist als der verfügbare Platz…

| | |<-[TextView Larger Than The Space Avail]| | | Die Textansicht hat einen Stil, der Folgendes festlegt: 

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

Es funktioniert also sollte, aber ich bin mir nicht sicher, welche Einschränkungen ich brauche, um das Bild nach rechts zu verschieben und dann Stop dort zu lassen und die Textansicht zu verstehen, dass kein Platz mehr vorhanden ist.

Was vermisse ich?

Hinweis: Wenn ich die Breite der Textansicht auf 0dp setze, funktioniert sie, aber das Bild ist immer auf der rechten Seite (horizontaler Bias scheint dafür ignoriert zu werden).

Anmerkung 2: Ich habe dies auch mit Beta2 ausprobiert, tatsächlich scheint es, als hätte Beta3 einen Fehler im visuellen Editor .

UPDATE: Ich habe versucht, dies in Xcode/AutoLayout zu replizieren:

So sieht es mit einem kurzen Text aus

 Short Text

Nun dasselbe Layout, ich tippe einfach einen langen Text in die Textansicht…

 Long Text

Wie Sie sehen, sagt die Randbedingung (rechts) für die Bildansicht: Sie sind 8 oder mehr Punkte vom rechten Rand. 

Es ist auch links neben der Beschriftung (textView) fixiert. 

Nach dem, was ich gerade von Twitter gelernt habe, ist dieses möglicherweise nicht möglich auf Android ConstraintLayout im Moment: Source

23

UPDATE JULI 2018:

Wenn Sie ConstraintLayout 1.1.0 verwenden, ist die korrekte zu verwendende Eigenschaft app:layout_constrainedWidth="true" anstelle des alten app:layout_constraintWidth_default="wrap" (und des Gegenstücks zur Höhe).

UPDATE NOVEMBER 2017

Ich verwende Constraint Layouts 1.0.2 und habe mit app:layout_constraintWidth_default="wrap" eine weniger geschachtelte Lösung gefunden (eine Eigenschaft, die in 1.0.0 eingeführt wurde, aber die Beta, die dieser Beitrag nicht verwendet hat).

Anstelle der FrameLayout, die eine LinearLayout enthält, können Sie jetzt alles entfernen und auf folgende Weise verwenden: 

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

Das macht genau das, was ich will, ohne Hacks oder Richtlinien oder hart codierte Größen. 

Die TextView verwendet die von den Constraints bereitgestellte Größe (was unter normalen Umständen bedeuten würde, dass sie entweder falsch ist oder über das 'Parent' hinauswächst), aber dank des neuen Attributs können diese Constraints gebogen/gebrochen werden, wenn das Inhalt ist kleiner/größer. 

Ich muss sagen, es funktioniert viel besser als iOS Priorities. (Zumindest ist es für mich viel einfacher zu verstehen) Daumen hoch für Google zu diesem Thema :)

ALTE ANTWORT (falls Sie es noch brauchen).

Basierend auf der Antwort von Nicolas Roard wollte ich einen benutzerdefinierten Container erstellen, der im Wesentlichen den verfügbaren Speicherplatz berechnet und die maxWidth-Funktion programmgesteuert in der TextView-Ansicht festlegt. Anstatt dem Projekt eine weitere Klasse, einen Unit-Test, einen möglichen Satz von Fehlern usw. hinzuzufügen, versuchte ich eine etwas weniger effiziente Methode, ein paar Layouts zu verschachteln. Wenn man bedenkt, dass wir seit dem Morgengrauen Layouts verschachtelt haben und dass dies in keiner Listenansicht oder in zu viel (oder gar nicht) Bewegungen der Fall sein wird, und dass ich ConstraintLayouts verwende, um den größten Teil der Hierarchie zu glätten (wie nie zuvor) !), dann glaube ich nicht, dass ein kleines Verschachteln bis dies besser unterstützt wird so schlimm ist. 

Was ich also getan habe, war im Grunde ein FrameLayout, das von design optimiert (oder gedacht) wurde, um ein Kind zu haben (das mehr enthalten kann). Dieses FrameLayout hat die ConstraintLayout-Regeln wie folgt angewendet: 

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

In meiner real - App befindet sich dieses FrameLayout in einem anderen ConstraintLayout, das links von ihm ein Symbol und ein paar andere Elemente enthält. Stellen Sie sich jedoch vor, Sie müssen links/rechts von "Pin" einstecken dieses FrameLayout zu dem Platz, den Sie belegen möchten. In diesem Beispiel können Sie sehen, dass ich parent in allen Einschränkungen verwende. Es können jedoch auch andere Widgets links und rechts von diesem FrameLayout vorhanden sein. Dank der Magie von ConstraintLayout nimmt dieser Platz den gesamten verfügbaren Platz ein.

Jetzt kommt der zweite Teil des Tricks… da ConstraintLayout garantiert, dass das FrameLayout "den gesamten Platz" verwendet, den wir haben, und niemals mehr (oder weniger), kann ich jetzt ein LinearLayout im Inneren verwenden ... wie 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>

Echte Leser werden feststellen, dass das LinearLayout wrap_content in der Breite hat. Dies ist sehr wichtig, da das untergeordnete TextView eine Breite von 0dp und eine weight von 1 haben kann, was bedeutet, dass alle verfügbarer freier Speicherplatz nach allen anderen Widgets) benötigt wird berechnete ihre Breite

In diesem speziellen Fall hat das andere untergeordnete Element (ImageView) caret keine Gewichtung und eine feste Breite. Daher muss der TextView den freien Speicherplatz nicht mit anderen Personen teilen/teilen, und er kann alles aufnehmen (aber nur freien Speicherplatz, denken Sie daran.) seine Breite beträgt 0dp). 

Dieser weniger effiziente Ansatz erreicht effektiv genau das, was ich wollte, wenn auch mit weniger ConstraintLayout Magic, wenn Sie so wollen.

Auf der positiven Seite musste ich keine benutzerdefinierte Ansicht erstellen, Mathematik ausführen und eine requestLayout() ausgeben, nachdem meine ganze Mathematik fertig war. Dieser weniger effiziente Ansatz wird/sollte skaliert werden und solange ConstraintLayout eine gültige Alternative bietet, kann es ausreichen, wie es ist. 

Setzen Sie sich mit den Google-Ingenieuren in Verbindung, die auf Social Media geantwortet haben und sich schließlich die Zeit nahmen, darüber nachzudenken. Vielleicht in der Zukunft, wenn sie Aufgaben und Story-Punkte zu ConstraintLayout 1.1 schreiben, erinnern sie sich daran und finden eine gute Lösung 

32

Eigentlich können Sie dies für TextViews tun - verwenden Sie Android:maxWidth:

<TextView
    Android:id="@+id/textView7"
    Android:maxWidth="200dp"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:maxLines="1"
    Android:ellipsize="end"
    Android:text="TextViewTextViewTextViewTextViewTextViewTextViewTextViewTextViewTextView"
    tools:layout_editor_absoluteY="72dp"
    Android:layout_marginStart="16dp"
    app:layout_constraintLeft_toLeftOf="parent"
    Android:layout_marginLeft="16dp" />

<Button
    Android:id="@+id/button20"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:text="Button"
    tools:layout_editor_absoluteY="56dp"
    Android:layout_marginStart="8dp"
    app:layout_constraintLeft_toRightOf="@+id/textView7"
    Android:layout_marginLeft="8dp" />

 enter image description here

Es ist nicht genau das, was Sie gefragt haben (Sie müssen wissen, dass die Breite begrenzt werden soll), aber es könnte Ihnen helfen, bis wir dies in ConstraintLayout selbst unterstützen.

3
Nicolas Roard

Sie können das relative Layout im Constraint-Layout mit negativem Rand für ImageView verwenden. Bitte beachten Sie Android:layout_marginRight="26dp" und Android:layout_marginLeft="-26dp"

<Android.support.constraint.ConstraintLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:orientation="vertical">

    <RelativeLayout
        Android:layout_width="0dp"
        Android:layout_height="wrap_content"
        Android:layout_margin="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            Android:id="@+id/textView"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_centerVertical="true"
            Android:layout_gravity="center_vertical"
            Android:layout_marginRight="26dp"
            Android:ellipsize="end"
            Android:gravity="start"
            Android:maxLines="1"
            Android:text="Some text" />

        <ImageView
            Android:id="@+id/imageView"
            Android:layout_width="24dp"
            Android:layout_height="24dp"
            Android:layout_centerVertical="true"
            Android:layout_marginLeft="-26dp"
            Android:layout_toRightOf="@+id/textView"
            Android:contentDescription=""
            Android:src="@drawable/ic_browser" />
    </RelativeLayout>

</Android.support.constraint.ConstraintLayout>

 enter image description here

Wenn der Text lang ist:  enter image description here

2
Dmitry

Diese Antwort ist von Martin Marconcinis Antwort ( https://stackoverflow.com/a/40491128/1151701 ) inspiriert. Um die Hierarchie zu reduzieren, können Sie das Constraint-Layout durch eine einfache Ansicht ersetzen.

      <TextView
        Android:ellipsize="end"
        Android:id="@+id/some_text"
        Android:layout_height="wrap_content"
        Android:layout_width="0dp"
        Android:lines="1"
        Android:maxLines="1"
        app:layout_constraintEnd_toStartOf="@+id/disclosure_arrow"
        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" /> 

      <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="@id/view_guide"
        app:layout_constraintStart_toEndOf="@id/some_text"
        app:layout_constraintTop_toBottomOf="@id/some_text"
        app:srcCompat="@drawable/your_vector_image" />

      <View
        Android:id="@+id/view_guide"
        Android:layout_width="0dp"
        Android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

Übrigens, ich benutze ConstraintLayout androidx.constraintlayout:constraintlayout:2.0.0-alpha3, aber app:layout_constrainedWidth="true" wird in diesem Fall wie erwartet gearbeitet. Also habe ich hier app:layout_constraintWidth_default="wrap" verwendet

0
Ali Mehrpour

In meinem Fall funktioniert das Update vom Juli 2018 von Martin nicht:

Wenn Sie ConstraintLayout 1.1.0 verwenden, ist die richtige zu verwendende Eigenschaft app:layout_constrainedWidth="true" anstelle des alten app:layout_constraintWidth_default="wrap" (und das Gegenstück zur Höhe)

Ich muss Android:width="wrap_content" für die Textansicht mit app:layout_constrainedWidth="true" verwenden. Android:layout_width="0dp" (match_constraint) bewirkt, dass die Textansicht in meinem Fall für kürzere Zeichenfolgen gestreckt wird.

Eine andere Möglichkeit, um dasselbe Ergebnis zu erzielen, wäre stattdessen Android:layout_width="0dp" mit dem Flag app:layout_constraintWidth_max="wrap" zu verwenden.

Weitere Informationen zu Flags für das Constraint-Layout finden Sie in doc: https://developer.Android.com/reference/Android/support/constraint/ConstraintLayout

0