ConstraintLayout内でタグ<include>
および<merge>
を使用すると問題が発生します。
フラットビュー階層(制約)を作成したいのですが、再利用可能な要素がまだあります。したがって、レイアウトで<include>
を使用し、含まれるレイアウトで<merge>
を使用して、ネストされたレイアウトを回避します(特にネストされたConstraintLayoutsを回避します)
だから私はこれを書いた:親レイアウト
<Android.support.constraint.ConstraintLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<include
Android:id="@+id/review_1"
layout="@layout/view_movie_note"
Android:layout_width="0dp"
Android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/review_2"/>
<include
layout="@layout/view_movie_note"
Android:id="@+id/review_2"
Android:layout_width="0dp"
Android:layout_height="0dp"
Android:layout_marginLeft="7dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/review_1"
app:layout_constraintRight_toRightOf="parent"
/>
</Android.support.constraint.ConstraintLayout>
そしてこのview_movie_note:
<merge>
<TextView
Android:id="@+id/note_Origin"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_marginBottom="15dp"
Android:layout_marginStart="5dp"
app:layout_constraintStart_toStartOf="@+id/cardView2"
app:layout_constraintTop_toTopOf="parent"
Android:layout_marginLeft="5dp" />
<Android.support.v7.widget.CardView
Android:id="@+id/five_star_view_container"
Android:layout_width="0dp"
Android:layout_height="52dp"
Android:layout_marginBottom="8dp"
Android:layout_marginTop="10dp"
Android:elevation="3dp"
app:cardUseCompatPadding="true"
app:contentPaddingTop="22dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_min="52dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/note_Origin">
<FiveStarsView
Android:id="@+id/five_star_view"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_gravity="center_horizontal" />
</Android.support.v7.widget.CardView>
<Android.support.v7.widget.CardView
Android:id="@+id/cardView2"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_marginTop="20dp"
app:cardBackgroundColor="@color/colorPrimary"
app:contentPaddingLeft="15dp"
app:contentPaddingRight="15dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/note_Origin">
<TextView
Android:id="@+id/grade"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:textSize="12sp" />
</Android.support.v7.widget.CardView>
</merge>
私はこれを期待しています
代わりに私はこれを得た
明らかに、<include>
タグに設定した制約は、含まれるレイアウトの制約によってオーバーライドされます。
これは予想される動作ですか?はいの場合、<include>
とConstraintLayoutを使用してフラットレイアウトをどのように維持するのですか?
最善の方法は、冗長レイアウト構造を使用するのではなく、<merge>
ブロックを(ネストされた)ConstraintLayout
に置き換えることです。
ConstraintLayoutは優れていますが、各部分の構成と責任の分離ではうまく機能しません
それは間違いです。 ConstraintLayout
は、レイアウトの再利用でうまく機能します。兄弟ビューと親レイアウトの関係に従ってすべての子ビューがレイアウトされるレイアウトは、このように動作します。これは、RelativeLayout
にも当てはまります。
<merge>
とは何かを詳しく見てみましょう。
ドキュメントは言う
<merge/>
タグは、あるレイアウトを別のレイアウトに含めるときに、ビュー階層内の冗長なビューグループを排除するのに役立ちます。
<include>
要素を<merge>
ブロックのコンテンツで置き換えるのと同じ効果があります。つまり、<merge/>
ブロック内のビューは、中間ビューグループなしで親レイアウトに直接配置されます。したがって、<include>
要素の制約は完全に無視されます。
この特定の例では、インクルードレイアウトのビューが、2番目のビューとして2回追加されます。
レイアウトリソースファイルは、独立して使用することを目的としています。再利用可能という用語を修飾するには、その親(将来的に追加されるビューグループ)に依存してはなりません。レイアウトを一度だけ含める必要がある場合は、問題ないように見えます。ただし、</merge>
は、別のレイアウトで別の位置に配置できないため、その場合も良いアイデアではありません。
明らかに、フラットレイアウト階層のパフォーマンスは向上しています。しかし、時にはそれを犠牲にしなければならないかもしれません。
Androidのドキュメント は言う
<merge />
タグは、1つのレイアウトを別のレイアウトに含めるときに、ビュー階層内の冗長なビューグループを排除するのに役立ちます
そして例もあります
メインレイアウトが2つの連続したビューを複数のレイアウトで再利用できる垂直
LinearLayout
である場合、2つのビューを配置する再利用可能なレイアウトには独自のルートビューが必要です。ただし、別のLinearLayout
を再利用可能なレイアウトのルートとして使用すると、垂直LinearLayout
内に垂直LinearLayout
が作成されます。ネストされたLinearLayout
は、UIのパフォーマンスを低下させること以外の本当の目的を果たしません。
この回答 も参照してください。これにより、マージタグの詳細がわかります。
子レイアウトの場合
<merge
タグ内の子要素に制約を設定します。それは大丈夫ではありません。なぜなら、両方の子レイアウトが親レイアウト内にマージされると、その制約は実行時に破棄されるからです。 (includeタグなしでこれを実行できる場合、制約は機能しますか?)
親レイアウトの場合
<include
タグについても同じです。制約/カスタム属性を<include
タグに与えていますが、これは<merge
タグがルートビューに結合されているため、<include
タグを使用して<merge
にカスタム属性を適用できません。 Bahman answerが機能するのはそのためです。
<include
タグの属性が機能する子レイアウト内にルート要素がある場合、および<merge
タグなし。
これが明らかなように、<merge
および<include
を使用しているわけではありません。 <include
および<merge
タグの機能を理解している。したがって、それらを適切に使用してください。
ConstraintLayout は、複雑なレイアウトを解決するために導入されました。複雑さを増やさないため。 LinearLayout
を使用して簡単にこれを行うことができる場合、なぜConstraints
。を選択するのか
親レイアウト
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
>
<include
Android:id="@+id/review_1"
layout="@layout/view_movie_note"
Android:layout_width="0dp"
Android:layout_height="wrap_content"
Android:layout_weight="1"
/>
<include
Android:id="@+id/review_2"
layout="@layout/view_movie_note"
Android:layout_width="0dp"
Android:layout_height="wrap_content"
Android:layout_marginLeft="7dp"
Android:layout_weight="1"
/>
</LinearLayout>
view_movie_note.xml
<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="wrap_content"
Android:layout_height="wrap_content">
<TextView
.../>
<Android.support.v7.widget.CardView
...
</Android.support.v7.widget.CardView>
<Android.support.v7.widget.CardView
...
</Android.support.v7.widget.CardView>
</Android.support.constraint.ConstraintLayout>
あなたによく理解していただければ幸いです。
解決策として
<?xml version="1.0" encoding="utf-8"?>
<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.support.v7.widget.LinearLayoutCompat
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:weightSum="2">
<include
Android:id="@+id/review_1"
layout="@layout/view_movie_note"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_weight="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/review_2"
app:layout_constraintTop_toTopOf="parent" />
<include
Android:id="@+id/review_2"
layout="@layout/view_movie_note"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_marginLeft="7dp"
Android:layout_weight="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/review_1"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</Android.support.v7.widget.LinearLayoutCompat>
</Android.support.constraint.ConstraintLayout>
view_movie_note
<?xml version="1.0" encoding="utf-8"?>
<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="wrap_content">
<TextView
Android:id="@+id/note_Origin"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_marginBottom="15dp"
Android:layout_marginLeft="5dp"
Android:layout_marginStart="5dp"
app:layout_constraintStart_toStartOf="@+id/cardView2"
app:layout_constraintTop_toTopOf="parent" />
<Android.support.v7.widget.CardView
Android:id="@+id/five_star_view_container"
Android:layout_width="wrap_content"
Android:layout_height="52dp"
Android:layout_marginBottom="8dp"
Android:layout_marginTop="10dp"
Android:elevation="3dp"
app:cardUseCompatPadding="true"
app:contentPaddingTop="22dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_min="52dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/note_Origin">
<!--<FiveStarsView-->
<!--Android:id="@+id/five_star_view"-->
<!--Android:layout_width="wrap_content"-->
<!--Android:layout_height="wrap_content"-->
<!--Android:layout_gravity="center_horizontal" />-->
<RatingBar
Android:id="@+id/ratingBar"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content" />
</Android.support.v7.widget.CardView>
<Android.support.v7.widget.CardView
Android:id="@+id/cardView2"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_marginTop="20dp"
app:cardBackgroundColor="@color/colorPrimary"
app:contentPaddingLeft="15dp"
app:contentPaddingRight="15dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/note_Origin">
<TextView
Android:id="@+id/grade"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:textSize="12sp" />
</Android.support.v7.widget.CardView>
</Android.support.constraint.ConstraintLayout>
include
タグをConstraintLayout
タグでラップしてから、include
タグの属性をこれらの新しいConstraintLayout
タグに移動します。
<Android.support.constraint.ConstraintLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.constraint.ConstraintLayout
Android:id="@+id/review_1"
Android:layout_width="0dp"
Android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/review_2">
<include layout="@layout/view_movie_note" />
</Android.support.constraint.ConstraintLayout>
<Android.support.constraint.ConstraintLayout
Android:id="@+id/review_2"
Android:layout_width="0dp"
Android:layout_height="0dp"
Android:layout_marginLeft="7dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/review_1"
app:layout_constraintRight_toRightOf="parent">
<include layout="@layout/view_movie_note" />
</Android.support.constraint.ConstraintLayout>
</Android.support.constraint.ConstraintLayout>
mergeはタグであり、ViewGroupではないため、インクルードに渡されるすべてのパラメーターは無視されます...このViewGroupは、複製されたレイアウトでのみフラット化できます。管理する必要がある場合は、 Group ... inflateを介したRelative LayoutへのマージレイアウトからのXML属性
ファイルview_movie_note.xml
は、ルートに単一のxmlノードを持つ必要があります。そうでない場合、制約に合わせて配置できるレイアウトノードは2つありません(<merge>
タグは役に立たない可能性があります)。同一のresId
を持つ2つの同一のレイアウトを持つことは問題に追加されます。これは、制約が常にresId
に対して定義されているためです。
代替アプローチは、a)2つのアイテムを水平方向に分配するために LinearLayout を使用することです-またはb)子ノードがさらにある場合(これを想定します) )、 GridView / RecyclerView 内で、2つの列を持つCardView
でGridLayout
sをより適切に使用します。
このような子レイアウトのルートノードとしての単一のCardView
は、適切に整列するために最も少なくなります。
予想される結果によると、ノードを整列するためにConstraintLayout
は必要ありません。GridLayoutManager
を使用すると、表示サイズに応じて列数を調整することもできます。要素の高さが異なる場合、StaggeredGridLayoutManager
もオプションになります。
原則として、フレームワークに対して作業するよりも、フレームワークに対して作業する方が常に簡単です。
あなたの質問に関するいくつかの問題:
また、インクルードレイアウトのルートビューのすべてのレイアウトパラメーター(Android:layout_ *属性)を<include />タグで指定することでオーバーライドできます。そのため、インクルードタグに設定した制約はすべて削除されます。
どれか Android:id
includeタグは、インクルードされたレイアウトでマージタグが使用されている場合は上書きされません。
制約の連鎖と追加は、異なるIDを持つビューで機能します。したがって、同じビューを同じ重みで複数回含めると、includeタグでは機能しません。
とはいえ、コピーして全体を貼り付けることもできます
したがって、この方法でincludeを使用することはできません。
次の3つのオプションがあります。
include
レイアウトのコンテンツをコピーして貼り付けますConstraintLayout
コードを変更してスプレッドチェーンをサポートします。IMO、これらのレイアウトの数が少ない場合は1番目のオプションが最適で、レイアウトが1つしかない場合は2番目のオプションが最適です(質問)、多数のレイアウトがある場合は3番目のオプションが最適です。