web-dev-qa-db-ja.com

ConstraintLayoutチェーンとテキスト省略記号+右側の画像

2018年7月更新:

ConstraintLayout 1.1.0を使用している場合、使用する正しいプロパティは、古いapp:layout_constrainedWidth="true"(および対応する高さ)の代わりにapp:layout_constraintWidth_default="wrap"です。更新された回答を参照してください。

2017年11月更新:

ConstraintLayout 1.0.0 stable(またはそれ以上)(現時点では1.0.2)を使用している場合、レイアウトをネストする必要のない、よりシンプルなソリューションについては、更新された回答を参照してください。

元の質問:

2016年11月3日にリリースされたConstraintLayouts-Beta3の使用。( source

私は次のことをしようとしています:

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

私はそのようなレイアウトで達成しました:

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

これは問題ないように見えますが、テキストが使用可能なスペースよりも長い場合は…

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

テキストビューには、これらを指定するスタイルがあります。

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

だからそれは動作するはずですが、右側までスライドさせてからstopまでどのような制約が必要かわかりませんそこにスペースがないことをテキストビューに認識させます。

私は何が欠けていますか?

注:textviewの幅を0dpに設定すると機能しますが、画像は常に右側になります(水平バイアスは無視されるようです)

注2: 私はこれをベータ2でも試しましたが、実際、ベータ3には ビジュアルエディタのバグ があるようです。

[〜#〜] update [〜#〜]:Xcode/AutoLayoutでこれを複製しようとしました:

これは短いテキストでどのように見えるかです

Short Text

同じレイアウトで、テキストビューに長いテキストを入力するだけです…

Long Text

あなたが見ることができるように、画像ビューのトレイル(右)制約は言う:あなたは右マージンから8以上ポイントです。

また、ラベル(textView)の左側に固定されています。

私がTwitterから学んだことから、現時点ではAndroidのConstraintLayoutではこれは不可能かもしれませんSource

29

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で導入されたが、この投稿で使用していたベータ版にはないプロパティ)を使用したネストの少ないソリューションを見つけました。

FrameLayoutを含む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>
_

これは、ハッキングやガイドライン、ハードコードされたサイズなしで、私が望むものを正確に実行します。

TextViewはConstraintsによって提供されるサイズを使用します(通常の状況では、これは間違っているか、「親」を超えて大きくなることを意味します)が、新しい属性のおかげで、これらの制約はコンテンツは小さい/大きい。

IOSの優先度よりもはるかに優れていると言わざるを得ません。 (少なくとも、私にとっては把握しやすいです)。この件についてGoogleに賛成:)

古い回答(まだ必要な場合)。

Nicolas Roardの答えに基づいて、基本的に使用可能なスペースを計算し、TextViewのmaxWidthをプログラムで設定するカスタムコンテナーを作成しました。別のクラス、単体テスト、バグの可能性のあるセットなどをプロジェクトに追加する代わりに、少し少ない効率的いくつかのレイアウトをネストする方法を試しました。夜明けからレイアウトをネストしており、これがスクロールリストビューに表示されたり移動したりすることはほとんどない(またはまったくない)ことと、ConstraintLayoutsを使用して階層のほとんどをフラット化することを考慮します(これまでにないように) !)、それから私は少し入れ子になっているとは思わないこれがより良くサポートされるまではそれは悪い。

つまり、基本的には、FrameLayoutを使用します。FrameLayoutは、設計上最適化(または考え)して、1人の子を作成します(複数の子を含めることができます)。この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>
_

したがって、私のrealアプリでは、このFrameLayoutは、左にアイコンやその他のものがある別のConstraintLayout内にありますが、この例のために、左/右を「固定」する必要があると想像してくださいこのFrameLayoutを、占有するスペースに合わせます。この例では、すべての制約でparentを使用していますが、このFrameLayoutの左右に他のウィジェットがある可能性があります。 ConstraintLayoutの魔法のおかげで、これはすべての使用可能なスペースを占有します。

次に、トリックの2番目の部分があります。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>
_

鋭い読者は、LinearLayoutの幅に_wrap_content_が含まれていることに気付くでしょう。これは、子TextViewが0dpの幅と1のweightを持つことができるために非常に重要です他のすべてのウィジェットが幅を計算した後に利用可能な空きスペース

この特定のケースでは、他の子(ImageView)caretには重みが指定されておらず、固定幅があるため、TextViewは他の人と空き領域を共有/分割する必要がなく、すべてを使用できます(ただし、空きスペースのみ。幅が0dpであることを思い出してください。

この非効率的アプローチは、ConstraintLayoutが少ないとはいえ、私が望むものを効果的に達成しますMagic.

プラス面として、カスタムビューを作成し、数学を実行し、すべての数学が完了した後にrequestLayout()を発行する必要はありませんでした。この非効率的なアプローチはスケーリングする/すべきであり、ConstraintLayoutが有効な代替手段を提供するまで、それで十分かもしれません。

ソーシャルメディアで返信し、最終的にはこれについて考える時間を取ったGoogleエンジニアへの叫び。将来、ConstraintLayout 1.1に関するタスクやストーリーポイントを書いているときに、彼らはこれを覚えており、良い解決策を考え出すかもしれません。

38

実際、TextViewsの場合の方法は次のとおりです。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

正確にあなたが尋ねたものではありません(幅を制限するためにサイズを知って設定する必要があります)が、ConstraintLayout自体でそれをサポートするまであなたを助けるかもしれません。

3
Nicolas Roard

ImageViewのマージンが負の制約レイアウトで相対レイアウトを使用できます。 Android:layout_marginRight="26dp"および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

テキストが長い場合: enter image description here

2
Dmitry

私の場合、2018年7月からのMartinからのアップデートは機能しません:

ConstraintLayout 1.1.0を使用している場合、使用する正しいプロパティは、古いapp:layout_constrainedWidth="true"(および対応する高さ)の代わりにapp:layout_constraintWidth_default="wrap"です。

Android:width="wrap_content"でのテキストビューにはapp:layout_constrainedWidth="true"を使用する必要があります。 Android:layout_width="0dp"(match_constraint)は、私の場合、短い文字列に合わせてテキストビューを拡大します。

同じ結果を得る別の可能性は、代わりにフラグAndroid:layout_width="0dp"app:layout_constraintWidth_max="wrap"を使用することです。

制約レイアウトのフラグの詳細については、ドキュメントをご覧ください: https://developer.Android.com/reference/Android/support/constraint/ConstraintLayout

1
MDikkii

この回答は、Martin Marconciniの回答( https://stackoverflow.com/a/40491128/1151701 )に触発されています。階層を削減するために、制約レイアウトを単純なビューに置き換えることができます。

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

ところで、私はConstraintLayout androidx.constraintlayout:constraintlayout:2.0.0-alpha3を使用していますが、app:layout_constrainedWidth="true"はこの場合期待どおりに機能します。ここでapp:layout_constraintWidth_default="wrap"を使用しました

0
Ali Mehrpour