Android ViewからComposableを使うと透過できない!という問題に遭遇した話
概要
こんにちは、@tonionagauzziです。
Androidの開発において、ViewとComposeを融合させる場面が増えています。
今回は、Android View内でComposableを使用する際に遭遇した、透過ができない問題とその解決策について説明します。
詳細
ComposeをAndroid View内で表示するために、ComposeViewを導入しました。
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
ところがアプリを起動すると、真っ黒な画面になってしまいました。
四隅parent
指定なので、さてはComposeViewを透明にし忘れたからだな…!?と思って、XMLでandroid:background
を設定しました。
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
しかし背景が透明にならなかったので、わかった!Composableの方か!と思ってそちらで背景を透明に設定してみました。
composeView.setContent {
Box(modifier = Modifier
.fillMaxSize()
.background(Color.Transparent)
) {
// ...
}
}
しかし、これでも透明になりませんでした。
この時点では、なぜだか全くわかりませんでした。
そこでLayout Inspectorを使ってView階層を確認してみると、ComposeViewとComposableの間にAndroidComposeViewという知らないViewが挟まれていることに気づきました。
さらに、そのViewが背景色を持っていることが判明しました。
原因
ズバリ問題の原因は、XML側の根元にあるConstraintLayoutにandroid:theme
が適用されていたことでした。
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_height="0dp"
android:layout_width="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:theme="@style/Theme.MyApp">
....
</androidx.constraintlayout.widget.ConstraintLayout>
<style name="Theme.MyApp" parent="Theme.MaterialComponents.Light.DarkActionBar">
<item name="android:textColor">@color/text</item>
<item name="android:textColorLink">@color/linkedText</item>
<item name="android:background">@color/background</item>
</style>
このTheme.MyApp
テーマが子ViewであるAndroidComposeViewにも適用されており、テーマにandroid:background
が設定されていたので、AndroidComposeViewに意図しない背景色が適用されていたというわけです。
ComposeView自体にはandroid:theme
を指定していないのに…!?というのがハマりポイントです。
解決方法
この問題を解決するために、根元のConstraintLayoutにはandroid:theme
を設定せず、入れ子のConstraintLayoutを持たせました。
<androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:theme="@style/Theme.MyApp">
<!--ここにテーマを設定したいViewを書く-->
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.compose.ui.platform.ComposeView />
</androidx.constraintlayout.widget.ConstraintLayout>
これによって、テーマ設定が必要なViewだけにandroid:theme
を適用することができました。
ComposeViewにはandroid:theme
の指定は不要です。
なぜならComposeView内ではMdc3Theme
などでComposeとしてのテーマ設定が可能だからです。
おわりに
AndroidComposeViewの存在に気付かず、少し時間を費やしてしまいました。
皆さんも背景が透明にならないと感じたときは、Layout InspectorでこのViewの存在を確認してみてください。
ComposeとAndroid Viewの組み合わせにおいて、予期せぬ振る舞いに出会ったこの経験が学びとして何かの役に立つことを願っています。
Discussion