androidx.constraintlayout.helper.widget.Flow知らんかった
不定の個数のViewを並べる&横幅いっぱいになったら改行するレイアウトが使いたい時に、
GridView(GridLayout)#numColumns(auto_fit)やChipGroupをカスタマイズしたりFlexboxLayoutを使っていたかと思うのですが、ConstraintLayout2.0
からFlowというLayoutが追加されていました(知らんかった)
さっそく使ってみます。
xmlで指定する場合
レイアウト
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="horizontal"
app:flow_wrapMode="chain"
app:constraint_referenced_ids="test1,test2,test3,test4,test5,test6"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/test1"
android:text="TEST"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
<TextView
android:id="@+id/test2"
android:text="TEST2"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
<TextView
android:id="@+id/test3"
android:text="TEST3"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
<TextView
android:id="@+id/test4"
android:text="TESTあああああああああ"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
<TextView
android:id="@+id/test5"
android:text="TEST5いいいいいいいいいいいい"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
<TextView
android:id="@+id/test6"
android:text="TEST6ううううううううううう"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
ConstraintLayoutの配下にFlowを置きます。
constraint_referenced_idsに表示したいレイアウトのidを指定します。
今回は横方向にViewを並べたかったのでandroid:orientation="horizontal"
を指定
また、横幅が足りない場合は改行して欲しかったのでapp:flow_wrapMode="chain"
を指定
しています。
画面
一行で収まらないtest5とtest6のViewだけが改行されました。
狙い通りです。
動的に指定する場合
画面全体のレイアウト
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraint"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.helper.widget.Flow
android:id="@+id/flow"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="horizontal"
app:flow_wrapMode="chain"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
同的に追加するレイアウト
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</layout>
コード
class MainActivity : AppCompatActivity() {
private val binding: MainActivityBinding by dataBinding()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
val test = (0..20).map { "test$it" }
val ids = IntArray(test.size)
test.forEachIndexed { index, text ->
val binding = ViewTextBinding.inflate(LayoutInflater.from(this))
val textView = binding.root as TextView
textView.text = text
textView.id = View.generateViewId()
this.binding.constraint.addView(textView)
ids[index] = textView.id
}
binding.flow.referencedIds = ids
}
}
同的に追加する時もxmlで指定するのとほぼ同じで、ConstraintLayout
に追加したいViewをAddします。
そして、FlowのreferencedIdsにViewのidを渡してあげれば完了です。
画面
マージンとかを知らない人みたいにはなりましたが、並びました
ちなみにマージンなどはxmlのFlowに↓の設定をしてもらうことで解決します。
app:flow_horizontalStyle="packed"
app:flow_horizontalGap="4dp"
app:flow_verticalGap="4dp"
本題
動的にViewを追加するコードの最後に
ids.forEach {
binding.constraint.removeView(binding.constraint.findViewById(it))
}
を追加しました。
あれ?消えてる・・・
いや、業務でやった時に消えてくれなくて泣いたんですよ!!
本当に泣いたんですって!!
信じて!!
Viewが消えなかった時の対処方法
ViewGroup#removeView(index)
は普通に動いてくれたので、そちらを使いました。
最後
いつもと違うFlowでした
おしまい
Discussion