Jetpack Compose 从入门到入门
Posted 唯鹿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jetpack Compose 从入门到入门相关的知识,希望对你有一定的参考价值。
本篇介绍如何将Jetpack Compose
添加到已有应用中,毕竟大多数情况都是在现有项目中使用。
Jetpack Compose 旨在配合既有的基于 View 的界面构造方式一起使用。如果您要构建新应用,最好的选择可能是使用 Compose 实现整个界面。但是,如果您要修改现有应用,那么请不要一次性迁移整个应用,而是可以将 Compose 与现有的界面设计实现相结合。
要将 Compose 与基于 View 的界面结合使用,有两种主要方法:
- 将 Compose 元素添加到现有界面中。具体方式是创建基于 Compose 的全新页面,或者将 Compose 元素添加到现有的 activity、fragment 或 View 布局中。
- 将基于 View 的界面元素添加到可组合函数中。如此一来,您便可在基于 Compose 的设计中添加 android View。
1.设置您的开发环境
首先就是引入项目中的配置,这部分可以参加本系列第一篇的项目配置。需要注意的是各版本的最低要求。
例如你使用Compose
1.2.0版本,compileSdk
需要最低到32、kotlin
版本最低1.7.0,gradle
最低7.2.0。还有Compose
需要的依赖,例如使用 activity-compose
依赖时,androidx.activity
最低为 1.3.0。
具体需要根据项目的情况来选择相应版本,不要因为引入 Compose
破坏了项目原本的稳定运行。
2.Interoperability API
1.View 中的 Compose
如果是创建基于 Compose
的全新页面,那就相对比较简单,就是我们第一篇的内容,activity
调用 setContent()
方法,传递相应的@Composable
函数。
我们看一个例子,如何将 Compose
元素添加到现有fragment布局中。首先将 ComposeView
添加到 XML 布局中:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/hello_world"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello Android!" />
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
代码获取 ComposeView
,设置适合宿主 View 的组合策略,并调用 setContent()
以使用 Compose
。
class ExampleFragment : Fragment()
private var _binding: FragmentExampleBinding? = null
// This property is only valid between onCreateView and onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View
_binding = FragmentExampleBinding.inflate(inflater, container, false)
val view = binding.root
binding.composeView.apply
setViewCompositionStrategy(DisposeOnViewTreeLifecycleDestroyed)
setContent
// In Compose world
MaterialTheme
Text("Hello Compose!")
return view
override fun onDestroyView()
super.onDestroyView()
_binding = null
调用 setViewCompositionStrategy
方法设置其他策略或创建自己的策略。例如DisposeOnLifecycleDestroyed
策略会在 lifecycle
被销毁时处理 Compose
。当 LifecycleOwner
未知时,可以使用 DisposeOnViewTreeLifecycleDestroyed
。
如果同一布局中存在多个 ComposeView
元素,每个元素必须具有唯一的 ID 才能使 savedInstanceState
发挥作用。ComposeView
ID 在 res/values/ids.xml
文件中进行定义。
class ExampleFragment : Fragment()
override fun onCreateView(...): View = LinearLayout(...).apply
addView(ComposeView(...).apply
id = R.id.compose_view_x
...
)
addView(TextView(...))
addView(ComposeView(...).apply
id = R.id.compose_view_y
...
)
2.Compose 中的 View
在 Compose
界面中添加 Android View ,比如项目中已有的自定义View等。这样就不需要重新去用Compose实现一遍了。
实现起来很简单,使用AndroidView
。系统会向 AndroidView
传递一个返回 View 的 lambda。AndroidView
还提供了在View填充时被调用的 update 回调。
@Composable
fun CustomView()
val selectedItem = remember mutableStateOf(0)
// Adds view to Compose
AndroidView(
modifier = Modifier.fillMaxSize(), // Occupy the max size in the Compose UI tree
factory = context ->
// Creates custom view
CustomView(context).apply
myView.setOnClickListener
selectedItem.value = 1
,
update = view ->
// 视图已被填充或读取的状态更新
// 当selectedItem在这里读取时,AndroidView将在状态改变时重新组合
view.coordinator.selectedItem = selectedItem.value
)
@Composable
fun ContentExample()
Column(Modifier.fillMaxSize())
Text("Look at this CustomView!")
CustomView()
如需嵌入XML布局,可以使用 androidx.compose.ui:ui-viewbinding
库提供的 AndroidViewBinding
API。
@Composable
fun AndroidViewBindingExample()
AndroidViewBinding(ExampleLayoutBinding::inflate)
exampleView.setBackgroundColor(Color.GRAY)
3.Compose 中的 fragment
添加Fragment可以使用FragmentContainerView
,将XML 属性 android:name
设置为 Fragment 的类名称。
例如定义 my_fragment_layout.xml
<androidx.fragment.app.FragmentContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container_view"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:name="com.example.MyFragment" />
然后就可以获取相应的Fragment:
@Composable
fun FragmentInComposeExample()
AndroidViewBinding(MyFragmentLayoutBinding::inflate)
val myFragment = fragmentContainerView.getFragment<MyFragment>()
// ...
3.共享使用
逐步迁移到 Compose
的过程中,可能需要在Compose
和 View
系统中使用共同的界面元素。比如我用Compose
写了一个名为CallToActionButton
的Button,如何在 Compose
和 View
中都使用?
@Composable
fun CallToActionButton(
text: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
)
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = MaterialTheme.colors.secondary
),
onClick = onClick,
modifier = modifier,
)
Text(text)
办法是需要创建一个继承 AbstractComposeView
的自定义VIew封装容器。
class CallToActionViewButton @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : AbstractComposeView(context, attrs, defStyle)
var text by mutableStateOf<String>("")
var onClick by mutableStateOf<() -> Unit>()
@Composable
override fun Content()
YourAppTheme
CallToActionButton(text, onClick)
具体调用:
class ExampleActivity : Activity()
private lateinit var binding: ActivityExampleBinding
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
binding = ActivityExampleBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.callToAction.apply
text = getString(R.string.something)
onClick = /* Do something */
4.Compose 调用 Android 框架
如果需要利用 Android 框架类,比如Context
、Service
,可以使用 CompositionLocal
的 current
属性访问前者当前值。例如,以下代码通过向 Toast.makeToast
方法提供 LocalContext.current
来显示消息框消息。
@Composable
fun ToastGreetingButton(greeting: String)
val context = LocalContext.current
Button(onClick =
Toast.makeText(context, greeting, Toast.LENGTH_SHORT).show()
)
Text("Greet")
除了LocalContext
外,还有LocalLifecycleOwner
、LocalView
等供我们直接使用。
对于Compose
来说,单向数据流模式非常适合它。所以MVI架构是一种不错的选择,后面有时间的话可以说说这块。
那么本篇到此结束,本系列也基本完成。官方文档总的来说还是比较详细的,本系列也算是官方文档的一个个人实践总结,希望可以帮到你。
看完后是不是从入门到入门,哈哈,具体还是需要多实践。
5.参考
以上是关于Jetpack Compose 从入门到入门的主要内容,如果未能解决你的问题,请参考以下文章