View 遷移至 Compose
主要學習內(nèi)容
- 如何逐步將應用遷移到 Compose
- 如何將 Compose 添加到使用 Android View 構建的現(xiàn)有界面
- 如何在 Compose 中使用 Android View
- 如何在 Compose 中使用 View 系統(tǒng)中的主題
原理
我們使用 Compose 都是在ComponentActivity
中調(diào)用setContent
方法硅则,那么與Activity的setContextView
有什么區(qū)別呢迹卢?
查看setContent
源碼:
public fun ComponentActivity.setContent(
parent: CompositionContext? = null,
content: @Composable () -> Unit
) {
//獲取decorView下的第一個子VIew
//顯然第一次啟動時 getChildAt(0) 返回null
val existingComposeView = window.decorView
.findViewById<ViewGroup>(android.R.id.content)
.getChildAt(0) as? ComposeView
if (existingComposeView != null) with(existingComposeView) {
setParentCompositionContext(parent)
setContent(content)
} else {
//會進入該分支
//創(chuàng)建ComposeView實例
ComposeView(this).apply {
// 在 setContentView 之前設置內(nèi)容和父項
// 讓 ComposeView 在 attach 時創(chuàng)建 composition
setParentCompositionContext(parent)
setContent(content)
// 在設置內(nèi)容視圖之前設置視圖樹Owner
// 以便 inflation process 和 attach listeners 能感知到它們存在
setOwners()
setContentView(this, DefaultActivityContentLayoutParams)
}
}
}
可以看到在setContent
方法中會去獲取ComposeView
對象晦闰,最后會去調(diào)用setContentView
筷屡,而這個setContentView
就是Activity的setContentView
方法
androidx.activity.ComponentActivity
@Override
public void addContentView(@SuppressLint({"UnknownNullness", "MissingNullability"}) View view,
@SuppressLint({"UnknownNullness", "MissingNullability"})
ViewGroup.LayoutParams params) {
initViewTreeOwners();
super.addContentView(view, params);
}
那么ComposeView
又是什么呢凰浮?
class ComposeView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AbstractComposeView(context, attrs, defStyleAttr){ ... }
abstract class AbstractComposeView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ViewGroup(context, attrs, defStyleAttr){ ... }
可以看到ComposeView
其實本質(zhì)上就是個ViewGroup
立叛,也就是說 Compose 中設置的界面最終會在ComposeView
上進行展示造壮,是 View和 Compose 的交界點
并不是說 Compose 可組合項最終都會變?yōu)閂iew吼过,而是可組合項形成的界面會在
ComposeView
上進行繪制顯示
在 View 中要使用 Compose 泼诱,只需要通過創(chuàng)建ComposeView
坛掠,在ComposeView
中通過setContent
調(diào)用可組合項就可以了
而在 Compose 中調(diào)用 View就會稍微麻煩一點,會在之后進行介紹
遷移規(guī)劃
要將 Jetpack Compose 集成到現(xiàn)有 Android 應用中治筒,有多種不同的方法屉栓。常用的兩種遷移策略為:
-
完全使用 Compose 開發(fā)一個新界面
在重構應用代碼以適應新技術時,一種常用的方法是只在應用構建的新功能中采用新技術耸袜,比較適合在創(chuàng)建新的界面使用該方法友多,原本的應用部分繼續(xù)使用 View 體系
-
選取一個現(xiàn)有界面,然后逐步遷移其中的各個組件
-
View作為外部布局
將部分界面遷移到 Compose堤框,讓其他部分保留在 View 系統(tǒng)中域滥,例如:遷移
RecyclerView
纵柿,同時將界面的其余部分保留在 View 系統(tǒng)中 -
Compose 作為外部布局
使用 Compose 作為外部布局,并使用 Compose 中可能沒有的一些現(xiàn)有 View启绰,比如
MapView
或AdView
-
準備工作
因為之后的代碼都是基于其中的項目進行的昂儒,而且遷移的學習是基于一個較完善的項目中進行,存在多個界面之間的切換
所以建議下載示例委可,并通過
Import Project
方式導入其中的MigrationCodelab
項目
在解壓文件中的MigrationCodelab
目錄中存放本次學習的案例代碼
在此學習中荆忍,我們將逐步把 Sunflower
的植物詳情界面遷移到 Compose,并 Compose 和 View 結合起來
添加 Compose 依賴
android {
...
kotlinOptions {
jvmTarget = '1.8'
useIR = true
}
buildFeatures {
...
compose true
}
composeOptions {
kotlinCompilerExtensionVersion rootProject.composeVersion
}
}
dependencies {
...
// Compose
implementation "androidx.compose.runtime:runtime:$rootProject.composeVersion"
implementation "androidx.compose.ui:ui:$rootProject.composeVersion"
implementation "androidx.compose.foundation:foundation:$rootProject.composeVersion"
implementation "androidx.compose.foundation:foundation-layout:$rootProject.composeVersion"
implementation "androidx.compose.material:material:$rootProject.composeVersion"
implementation "androidx.compose.runtime:runtime-livedata:$rootProject.composeVersion"
implementation "androidx.compose.ui:ui-tooling:$rootProject.composeVersion"
implementation "com.google.android.material:compose-theme-adapter:$rootProject.composeVersion"
...
}
初步遷移 Compose
在植物詳情界面中撤缴,我們需要將對植物的說明遷移到 Compose,同時讓界面的總體結構保持完好
Compose 需要有 activity 或 fragment 才能呈現(xiàn)界面叽唱。在 Sunflower 中屈呕,所有界面都使用 fragment,因此我們需要使用 ComposeView
ComposeView
可以使用setContent
方法托管 Compose 界面內(nèi)容
這里我們選取植物詳情界面棺亭,然后逐步遷移其中的各個組件
移除XML代碼
打開 fragment_plant_detail.xml
并執(zhí)行以下操作:
- 切換到
code
視圖 - 移除
NestedScrollView
中的ConstraintLayout
代碼和嵌套的TextView
(建議使用代碼注釋的方式虎眨,方便進行比較和遷移) - 添加一個
ComposeView
,它會改為托管 Compose 代碼镶摘,并以compose_view
作為 id
fragment_plant_detail.xml
<androidx.core.widget.NestedScrollView
android:id="@+id/plant_detail_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="@dimen/fab_bottom_padding"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<!-- 其余部分全部注釋掉 -->
<!-- 這里就不展示注釋部分 -->
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.core.widget.NestedScrollView>
添加Compose代碼
在該項目中嗽桩,我們可以將 Compose 代碼添加到 plantdetail
文件夾下的 PlantDetailDescription.kt
文件中
plantdetail/PlantDetailDescription.kt
//文件中原本存在的可組合項函數(shù)
@Composable
fun PlantDetailDescription() {
Surface {
Text("Hello Compose")
}
}
我們要在ComposeView
中調(diào)用PlantDetailDescription
可組合項
在plantdetail/PlantDetailFragment.kt
中凄敢,訪問 composeView
并調(diào)用 setContent
,以便在界面上顯示 Compose 代碼
Sunflower 項目中使用
DataBinding
的方式滩援,我們可以直接訪問composeView
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = DataBindingUtil.inflate<FragmentPlantDetailBinding>(
inflater, R.layout.fragment_plant_detail, container, false
).apply {
...
composeView.setContent {
MaterialTheme {
PlantDetailDescription()
}
}
}
setHasOptionsMenu(true)
return binding.root
}
運行該應用,界面上會顯示“Hello Compose!
”
從XML映射到可組合項
我們首先遷移植物的名稱憎蛤。更確切地說碾盟,是在 fragment_plant_detail.xml
中 ID 為 @+id/plant_detail_name
的 TextView
<TextView
android:id="@+id/plant_detail_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_small"
android:layout_marginEnd="@dimen/margin_small"
android:gravity="center_horizontal"
android:text="@{viewModel.plant.name}"
android:textAppearance="?attr/textAppearanceHeadline5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Apple" />
我們根據(jù)XML中的樣式創(chuàng)建的新 PlantName
可組合項與之對應
@Composable
private fun PlantName(name: String) {
Text(
text = name,
style = MaterialTheme.typography.h5,
modifier = Modifier
.fillMaxWidth()
.padding(
start = dimensionResource(id = R.dimen.margin_small),
end = dimensionResource(id = R.dimen.margin_small)
)
.wrapContentWidth(Alignment.CenterHorizontally)
)
}
映射關系:
-
Text
的樣式為MaterialTheme.typography.h5
熙尉,從 XML 代碼映射到textAppearanceHeadline5
锨推。 - 修飾符會修飾 Text,以將其調(diào)整為類似于 XML 版本:
-
fillMaxWidth
修飾符對應于 XML 代碼中的android:layout_width="match_parent"
-
margin_small
的水平padding
,其值是使用dimensionResource
輔助函數(shù)從 View 系統(tǒng)獲取的 -
wrapContentWidth
水平對齊Text
-
如何觀察
LiveData
將在稍后介紹磁椒,因此先假設我們有可用的名稱
通過預覽查看效果
@Preview(showBackground = true, backgroundColor = 0XFFFFFF)
@Composable
private fun PlantNamePreview() {
MaterialTheme {
PlantName("Apple")
}
}
ViewModel和LiveData
現(xiàn)在医增,我們將PlantName
顯示到界面。如需執(zhí)行此操作夺欲,我們需要使用 PlantDetailViewModel
加載數(shù)據(jù)
ViewModel
由于 fragment 中使用了 PlantDetailViewModel
的實例市埋,因此我們可以將其作為參數(shù)傳遞給 PlantDetailDescription
@Composable
fun PlantDetailDescription(plantDetailViewModel: PlantDetailViewModel) {
...
}
在 fragment 調(diào)用此可組合項時傳遞 ViewModel
實例:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = DataBindingUtil.inflate<FragmentPlantDetailBinding>(
inflater, R.layout.fragment_plant_detail, container, false
).apply {
...
composeView.setContent {
MaterialTheme {
PlantDetailDescription(plantDetailViewModel)
}
}
}
...
}
可組合項沒有自己的
ViewModel
實例,相應的實例將在可組合項和托管 Compose 代碼的生命周期所有者(activity 或 fragment)之間共享
如果您遇到了 ViewModel 無法使用的情況镣陕,或者您不希望將該依賴項傳遞給可組合項,則可以在可組合項中使用 viewModel
函數(shù),以獲取 ViewModel 的實例
如需使用
viewModel()
函數(shù)耀销,請將androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1
依賴項添加到build.gradle
文件中
class ExampleViewModel : ViewModel() { /*...*/ }
@Composable
fun MyExample(
viewModel: ExampleViewModel = viewModel()
) {
...
}
viewModel()
會返回一個現(xiàn)有的 ViewModel
,或在給定作用域內(nèi)創(chuàng)建一個新的 ViewModel肮蛹。只要該作用域處于有效狀態(tài)勺择,就會保留 ViewModel
例如,如果在某個 Activity 中使用了可組合項蔗崎,則在該 Activity 完成或進程終止之前酵幕,viewModel()
會返回同一實例
如果 ViewModel 具有依賴項,則 viewModel()
會將可選的 ViewModelProvider.Factory
作為參數(shù)
如需詳細了解 Compose 中的
ViewModel
以及實例如何與 Compose Navigation 庫或 activity 和 fragment 一起使用缓苛,請參閱互操作性文檔
LiveData
PlantDetailDescription
可以通過PlantDetailViewModel
的 LiveData<Plant>
字段芳撒,以獲取植物的名稱
如需從可組合項觀察 LiveData,請使用 LiveData.observeAsState()
函數(shù)
LiveData.observeAsState()
開始觀察LiveData
未桥,并通過State
對象表示它的值笔刹。每次向LiveData
發(fā)布一個新值時,返回的State
都會更新冬耿,這會導致所有State.value
用法重組
由于 LiveData 發(fā)出的值可以為 null舌菜,因此我們需要將其用法封裝在 null 檢查中。有鑒于此亦镶,以及為了實現(xiàn)可重用性日月,最好將 LiveData 的使用和監(jiān)聽拆分到不同的可組合項中
因此,我們創(chuàng)建 PlantDetailDescription
的新可組合項缤骨,用于顯示 Plant
信息
@Composable
fun PlantDetailDescription(plantDetailViewModel: PlantDetailViewModel) {
val plant by plantDetailViewModel.plant.observeAsState()
plant?.let {
PlantDetailContent(it)
}
}
@Composable
fun PlantDetailContent(plant: Plant) {
PlantName(plant.name)
}
遷移更多XML代碼
現(xiàn)在我們繼續(xù)遷移ConstraintLayout
中的 View:澆水信息和植物說明
fragment_plant_detail.xml
中澆水信息 XML 代碼由兩個 ID 為 plant_watering_header
和 plant_watering
的 TextView 組成
<TextView
android:id="@+id/plant_watering_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_small"
android:layout_marginTop="@dimen/margin_normal"
android:layout_marginEnd="@dimen/margin_small"
android:gravity="center_horizontal"
android:text="@string/watering_needs_prefix"
android:textColor="?attr/colorAccent"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/plant_detail_name" />
<TextView
android:id="@+id/plant_watering"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_small"
android:layout_marginEnd="@dimen/margin_small"
android:gravity="center_horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/plant_watering_header"
app:wateringText="@{viewModel.plant.wateringInterval}"
tools:text="every 7 days" />
和之前的操作類似爱咬,創(chuàng)建 PlantWatering
新可組合項,以在界面上顯示澆水信息:
@Composable
fun PlantWatering(wateringInterval: Int) {
Column(Modifier.fillMaxWidth()) {
val centerWithPaddingModifier = Modifier
.padding(horizontal = dimensionResource(R.dimen.margin_small))
.align(Alignment.CenterHorizontally)
val normalPadding = dimensionResource(R.dimen.margin_normal)
Text(
text = stringResource(R.string.watering_needs_prefix),
color = MaterialTheme.colors.primaryVariant,
fontWeight = FontWeight.Bold,
modifier = centerWithPaddingModifier.padding(top = normalPadding)
)
val wateringIntervalText = LocalContext.current.resources.getQuantityString(
R.plurals.watering_needs_suffix, wateringInterval, wateringInterval
)
Text(
text = wateringIntervalText,
modifier = centerWithPaddingModifier.padding(bottom = normalPadding)
)
}
}
由于
Text
可組合項會共享水平內(nèi)邊距和對齊修飾绊起,因此您可以將修飾符分配給局部變量(即centerWithPaddingModifier
)精拟,以重復使用修飾符。修飾符是標準的 Kotlin 對象虱歪,因此可以重復使用Compose 的
MaterialTheme
與plant_watering_header
中使用的colorAccent
不完全匹配》湟铮現(xiàn)在,我們可以使用將在主題設置部分中加以改進的MaterialTheme.colors.primaryVariant
我們將各個部分組合在一起笋鄙,然后同樣在 PlantDetailContent
中調(diào)用 PlantWatering
师枣,因為ConstraintLayout
還有 margin
值,我們還需要將值添加到 Compose 代碼中
為了確保背景顏色和所用的文本顏色均合適萧落,我們需要添加 Surface
用于處理這種設置
@Composable
fun PlantDetailContent(plant: Plant) {
Surface {
Column(Modifier.padding(dimensionResource(R.dimen.margin_normal))) {
PlantName(plant.name)
PlantWatering(plant.wateringInterval)
}
}
}
@Preview(showBackground = true, backgroundColor = 0XFFFFFF)
@Composable
private fun PlantNamePreview() {
val plant = Plant("id", "Apple", "description", 3, 30, "")
MaterialTheme {
PlantDetailContent(plant)
}
}
刷新預覽
Compose 中調(diào)用View
接下來坛吁,我們來遷移植物說明
<TextView
android:id="@+id/plant_description"
style="?android:attr/textAppearanceMedium"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_small"
android:layout_marginTop="@dimen/margin_small"
android:layout_marginEnd="@dimen/margin_small"
android:minHeight="@dimen/plant_description_min_height"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/plant_watering"
app:renderHtml="@{viewModel.plant.description}"
tools:text="Details about the plant" />
TextView中包含了app:renderHtml="@{viewModel.plant.description}"
,renderHtml
是一個綁定適配器铐尚,可在 PlantDetailBindingAdapters.kt
文件中找到拨脉。該實現(xiàn)使用 HtmlCompat.fromHtml
在 TextView
上設置文本
@BindingAdapter("wateringText")
fun bindWateringText(textView: TextView, wateringInterval: Int) {
val resources = textView.context.resources
val quantityString = resources.getQuantityString(
R.plurals.watering_needs_suffix,
wateringInterval, wateringInterval
)
textView.text = quantityString
}
但是,Compose 目前不支持 Spanned
類宣增,也不支持顯示 HTML 格式的文本玫膀。因此,我們需要在 Compose 代碼中使用 View 系統(tǒng)中的 TextView
來繞過此限制
由于 Compose 目前還無法呈現(xiàn) HTML 代碼爹脾,因此您需要使用 AndroidView
API 程序化地創(chuàng)建一個 TextView
帖旨,從而實現(xiàn)此目的
AndroidView
接受程序化地創(chuàng)建的 View箕昭。如果您想嵌入 XML 文件,可以結合使用視圖綁定與androidx.compose.ui:ui-viewbinding
庫中的AndroidViewBinding
API
創(chuàng)建 PlantDescription
可組合項解阅。此可組合項中使用 AndroidView
創(chuàng)建TextView
落竹。在 factory
回調(diào)中,請初始化使用給定 Context
來回應 HTML 交互的 TextView
货抄。在 update
回調(diào)中述召,用已保存的 HTML 格式的說明設置文本
@Composable
private fun PlantDescription(description: String) {
// Remembers the HTML formatted description. Re-executes on a new description
val htmlDescription = remember(description) {
//使用 HtmlCompat 解析 html
//HtmlCompat 內(nèi)部做了版本適配
HtmlCompat.fromHtml(description, HtmlCompat.FROM_HTML_MODE_COMPACT)
}
// 在屏幕上顯示 TextView 并在 inflate 時使用 HTML 描述進行更新
// 對 htmlDescription 的更新將使 AndroidView 重新組合并更新文本
AndroidView(
factory = { context ->
TextView(context).apply {
//對于鏈接點擊的處理,若不設置movementMethod蟹地,則鏈接無效
movementMethod = LinkMovementMethod.getInstance()
}
},
update = {
it.text = htmlDescription
}
)
}
remember
中將description
作為 key 积暖,如果 description
參數(shù)發(fā)生變化,系統(tǒng)會再次執(zhí)行 remember
中的 htmlDescription
代碼
同樣怪与,如果 htmlDescription
發(fā)生變化夺刑,AndroidView
更新回調(diào)會重組。在回調(diào)中讀取的任何狀態(tài)都會導致重組
我們將 PlantDescription
添加到 PlantDetailContent
可組合項
@Composable
fun PlantDetailContent(plant: Plant) {
Column(Modifier.padding(dimensionResource(id = R.dimen.margin_normal))) {
PlantName(plant.name)
PlantWatering(plant.wateringInterval)
PlantDescription(plant.description)
}
}
現(xiàn)在分别,我們就將原始 ConstraintLayout
中的所有內(nèi)容遷移到 Compose了
ViewCompositionStrategy
默認情況下遍愿,只要 ComposeView
與窗口分離,Compose 就會處理組合耘斩。Compose 界面 View
類型(例如 ComposeView
和 AbstractComposeView
)使用定義此行為的 ViewCompositionStrategy
默認情況下沼填,Compose 使用 DisposeOnDetachedFromWindow
策略。但是煌往,在 Compose 界面 View 類型用于以下各項的部分情況下,默認策略可能不太合適:
- Fragment轧邪。Compose 界面
View
類型應該遵循 fragment 的視圖生命周期去保存狀態(tài) - Transitions 動畫刽脖。當 Transitions 過程中使用 Compose 界面
View
類型,系統(tǒng)會在轉(zhuǎn)換開始(而不是轉(zhuǎn)換結束)時將其與窗口分離忌愚,從而導致可組合項在它仍然在屏幕上時就開始 detach -
RecyclerView
或者帶有生命周期管理的自定義控件
在上述某些情況下曲管,除非您手動調(diào)用 AbstractComposeView.disposeComposition
,否則應用可能會因為組合實例泄漏內(nèi)存
如需在不再需要組合時自動處理組合硕糊,請通過調(diào)用 setViewCompositionStrategy
方法設置其他策略或創(chuàng)建自己的策略
例如院水,DisposeOnLifecycleDestroyed
策略會在 lifecycle
被銷毀時處理組合
此策略適用于與已知的 LifecycleOwner
具有一對一關系的 Compose 界面 View
類型
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = DataBindingUtil.inflate<FragmentPlantDetailBinding>(
inflater, R.layout.fragment_plant_detail, container, false
).apply {
...
composeView.apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnLifecycleDestroyed(this@PlantDetailFragment.lifecycle))
setContent {
PlantDetailDescription(plantDetailViewModel)
}
}
}
...
}
當 LifecycleOwner
未知時,可以使用 DisposeOnViewTreeLifecycleDestroyed
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = DataBindingUtil.inflate<FragmentPlantDetailBinding>(
inflater, R.layout.fragment_plant_detail, container, false
).apply {
...
composeView.apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
PlantDetailDescription(plantDetailViewModel)
}
}
}
...
}
如需了解如何使用此 API简十,請參閱“Fragment 中的 ComposeView”部分
互操作性主題設置
我們已將植物詳情的文本內(nèi)容遷移到 Compose檬某。不過,Compose 使用的主題顏色有誤螟蝙。當植物名稱應該使用綠色時恢恼,它使用的是紫色
顯然 View 體系使用的主題和MaterialTheme
并沒有進行關聯(lián),我們需要 Compose 繼承 View 系統(tǒng)中可用的主題胰默,而不是從頭開始在 Compose 中重新編寫您自己的 Material 主題
<style name="Base.Theme.Sunflower" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">@color/sunflower_green_500</item>
<item name="colorPrimaryVariant">@color/sunflower_green_700</item>
<item name="colorOnPrimary">@color/sunflower_black</item>
<item name="colorPrimaryDark">@color/sunflower_green_700</item>
<item name="colorAccent">?attr/colorPrimaryVariant</item>
<item name="colorSecondary">@color/sunflower_yellow_500</item>
<item name="colorOnSecondary">@color/sunflower_black</item>
<item name="android:colorBackground">@color/sunflower_green_500</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:navigationBarColor">?colorOnSurface</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
如需在 Compose 中重復使用 View 系統(tǒng)的 Material Design 組件 (MDC) 主題场斑,您可以使用 compose-theme-adapter
漓踢。MdcTheme
函數(shù)將自動讀取主機上下文的 MDC 主題,并代表您將它們傳遞給 MaterialTheme
漏隐,以用于淺色和深色主題
dependencies {
...
implementation "com.google.android.material:compose-theme-adapter:$rootProject.composeVersion"
...
}
如需使用此庫喧半,請將 MaterialTheme
的用法替換為 MdcTheme
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = DataBindingUtil.inflate<FragmentPlantDetailBinding>(
inflater, R.layout.fragment_plant_detail, container, false
).apply {
...
composeView.apply {
...
setContent {
MdcTheme {
PlantDetailDescription(plantDetailViewModel)
}
}
}
}
...
}