上面的参数都是可选参数,还有像背景设置等的参数并不是对实际的App进行设置,只是对Preview中的背景进行设置,为了更容易看清布局。
@Preview(showBackground = true)
@Composable fun DefaultPreview() {
ComposeDemoTheme {
Greeting(“Android”)
}
}
当更改跟UI相关的代码时,会显示如下图的一个横条通知,点击Build&Refresh即可更新显示所更改代码的UI。
setContent
该方法作用是和zaiLayout/View中的setContentView是一样的。setContent的方法也是有@Compose注解的方法。所以,在setContent中写入关于UI的@Compopse方法,即可在Activity中显示。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Text(“Hello world!”)
}
}
Modifier
该类
是各个Compose
的UI组件一定会用到的一个类。它是被用于设置UI的摆放位置,padding等修饰信息的类。关于Modifier
相关的设置较多,在这里只介绍会经常用到的。
Modifier.padding(10.dp) // 给上下左右设置成同一个值
Modifier.padding(10.dp, 11.dp, 12.dp, 13.dp) // 分别为上下左右设值
Modifier.padding(10.dp, 11.dp) // 分别为上下和左右设值
Modifier.padding(InnerPadding(10.dp, 11.dp, 12.dp, 13.dp))// 分别为上下左右设值
Modifier.fillMaxHeight() // 填充整个宽度
Modifier.fillMaxHeight() // 填充整个高度
Modifier.fillMaxSize() // 填充整个宽度和高度
Modifier.width(2.dp) // 设置宽度
Modifier.height(3.dp) // 设置高度
Modifier.size(4.dp, 5.dp) // 设置高度和宽度
Modifier.widthIn(2.dp) // 设置最大宽度
Modifier.heightIn(3.dp) // 设置最大高度
Modifier.sizeIn(4.dp, 5.dp, 6.dp, 7.dp) // 设置最大最小的宽度和高度
Modifier.gravity(Alignment.CenterHorizontally) // 横向居中
Modifier.gravity(Alignment.Start) // 横向居左
Modifier.gravity(Alignment.End) // 横向居右
Modifier.rtl // 从右到左 Modifier.ltr // 从左到右
Modifier.plus(otherModifier) // 把otherModifier的信息加入到现有的modifier中
// Modifier的方法都返回Modifier的实例的链式调用,所以只要连续调用想要使用的方法即可。
@Composable fun Greeting(name: String) {
Text(text = “Hello $name!”, modifier = Modifier.padding(20.dp).fillMaxWidth())
}
Column,Row
Column和Row可以理解为在View/Layout体系中的纵向和横向的ViewGroup
Column(
verticalArrangement:Arrangement // 控制纵向布局关系
horizontalAlignment:Alignment // 控制横向对齐关系
)
Row(
horizontalArrangement:Alignment // 控制横向布局关系
verticalAlignment:Arrangement // 控制纵向对齐关系
)
@Composable
fun TestColumnRow() {
Column(
modifier = Modifier.fillMaxHeight().background(Color.Yellow),
verticalArrangement = Arrangement.SpaceBetween,
horizontalAlignment = Alignment.Start
) {
Text(text = “java”)
Text(text = “android”)
Text(text = “python”)
}
Row(
modifier = Modifier.fillMaxWidth().background(Color.LightGray),
verticalAlignment = Alignment.Top,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(text = “java”)
Text(text = “android”)
Text(text = “python”)
}
}
四、进阶使用
状态管理
所有 Android 应用都有核心界面更新循环,如下所示:
Compose 专为单向数据流而打造。这是一种状态向下流动而事件向上流动的设计。
使用单向数据流的应用的界面更新循环如下所示:
事件:事件由界面的一部分生成并且向上传递。
更新状态:事件处理脚本可以更改状态。
显示状态:状态会向下传递,界面会观察新状态并显示该状态。
举两个例子展示:
//内部状态管理
@Composable
fun CounterInner() {
val count = remember { mutableStateOf(0) }
Button(onClick = { count.value += 1 })
{
Text(text = “Count: ${count.value}”)
}
}
解释一下上图的数据流情况
事件:当点击发生时候,会触发count.value
更新状态:mutableStateOf会进行处理,然后设置count的状态
显示状态:系统会调用count的观察器,并且界面会显示新状态
//支持其他可观察类型的状态管理
class CountViewModel : ViewModel() {
// LiveData holds state which is observed by the UI
// (state flows down from ViewModel)
private val _count = MutableLiveData(0)
val count: LiveData = _count
// onNameChanged is an event we’re defining that the UI can invoke
// (events flow up from UI)
fun onCountChanged(newCount: Int) {
_count.value = newCount
}
}
@Composable
fun Counter(countViewModel: CountViewModel = viewModel()) {
val observeAsState = countViewModel.count.observeAsState(0)
val count = observeAsState.value
Button(
colors = ButtonConstants.defaultButtonColors(backgroundColor = if (count > 5) Color.Green else Color.White),
onClick = { countViewModel.onCountChanged(count + 1) },
) {
Text(text = “I’ve been clicked $count times”)
}
}
解释一下上图的数据流情况
事件:当点击发生时候,会触发onCountChanged
更新状态:onCountChanged会进行处理,然后设置_count的状态
显示状态:系统会调用count的观察器,并且界面会显示新状态
状态提升
-
无状态可组合项是指本身无法改变任何状态的可组合项。无状态组件更容易测试、发生的错误往往更少,并且更有可能重复使用。
-
如果您的可组合项有状态,您可以通过使用状态提升使其变为无状态。
-
状态提升是一种编程模式,在这种模式下,通过将可组合项中的内部状态替换为参数和事件,将状态移至可组合项的调用方。
-
状态提升的过程可让您将单向数据流扩展到无状态可组合项。在这些可组合项的单向数据流示意图中,随着更多可组合项与状态交互,状态仍向下流动,而事件向上流动。
@Composable
fun Counter(countViewModel: CountViewModel = viewModel()) {
val observeAsState = countViewModel.count.observeAsState(0)
val count = observeAsState.value
ButtonCount(count = count, onCountChanged = { countViewModel.onCountChanged(it) })
}
@Composable
fun ButtonCount(
/* state */ count: Int,
/* event */ onCountChanged: (Int) -> Unit ) {
Button(
colors = ButtonConstants.defaultButtonColors(backgroundColor = if (count > 5) Color.Green else Color.White),
onClick = { onCountChanged(count + 1) },
) {
Text(text = “I’ve been clicked $count times”)
}
}
互操作
Android View中的Compose
如果想使用Compose的情况下,又不想迁移整个应用,可以在xml里面增加ComposeView,类似于占位符,然后在Actviity/fragment中寻找该控件并调用setContent方法即可,在该方法中即可使用compose相关属性
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android=“http://schemas.android.com/apk/res/android”
xmlns:app=“http://schemas.android.com/apk/res-auto”
xmlns:tools=“http://schemas.android.com/tools”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
tools:context=“.AndroidViewComposeActivity”>
<TextView
android:id=“@+id/hello_world”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
android:text=“Hello Android!”
app:layout_constraintTop_toTopOf=“parent” />
<androidx.compose.ui.platform.ComposeView
android:id=“@+id/compose_view_text”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
app:layout_constraintTop_toBottomOf=“@id/hello_world” />
<androidx.compose.ui.platform.ComposeView
android:id=“@+id/compose_view_img”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
app:layout_constraintTop_toBottomOf=“@id/compose_view_text” />
</androidx.constraintlayout.widget.ConstraintLayout>
class AndroidViewComposeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_android_view_compose)
findViewById(R.id.compose_view_text).setContent {
MaterialTheme {
Text(“Hello Compose!”)
}
}
findViewById(R.id.compose_view_img).setContent {
val imageResource = imageResource(id = R.drawable.header)
val imageModifier = Modifier.preferredHeight(180.dp)
.fillMaxWidth()
.padding(16.dp)
.clip(RoundedCornerShape(4.dp))
MaterialTheme {
Image(
bitmap = imageResource,
modifier = imageModifier,
contentScale = ContentScale.Crop
)
}
}
}
}
Compose中的Android View
如果碰到在Compose环境中,想要使用Android的View视图的情况,只需要使用AndroidView函数即可
@Composable
fun CustomView() {
val selectedItem = remember { mutableStateOf(0) }
val context = AmbientContext.current
val customView = remember {
// Creates custom view
Button(context).apply {
// Sets up listeners for View -> Compose communication
setOnClickListener {
selectedItem.value += 1
}
}
}
// Adds view to Compose
AndroidView({ customView }) {
view ->
// View’s been inflated - add logic here if necessary
// As selectedItem is read here, AndroidView will recompose
// whenever the state changes
// Example of Compose -> View communication
view.text = selectedItem.value.toString()
}
}
如果是需要使用xml的配置情况,也使用AndroidView函数即可
@Composable
fun CustomView2() {
val context = AmbientContext.current
val customView = remember {
// Creates custom view
View.inflate(context, R.layout.layout_custom_view, null)
}
AndroidView({ customView })
}
与通用库集成
ViewModel
从源码可看出,viewmodel函数底层也是通过ViewModelProvider进行获取的
@Composable
fun viewModel(
modelClass: Class,
key: String? = null,
-
factory: ViewModelProvider.Factory? = null )
- VM = AmbientViewModelStoreOwner.current.get(modelClass, key, factory)
数据流
Compose也是适配Android主流的基于流的方案,如
-
LiveData.observeAsState()
-
Flow.collectAsState()
-
Observable.subscribeAsState()
在Compose中,LiveData.observeAsState()获取的State对象赋值给Text
@Composable
fun HelloScreen(helloViewModel: HelloViewModel = viewModel()) {
// by default, viewModel() follows the Lifecycle as the Activity or Fragment
// that calls HelloScreen(). This lifecycle can be modified by callers of HelloScreen.
// name is the current value of [helloViewModel.name]
// with an initial value of “”
val observeAsState = helloViewModel.name.observeAsState(“”)
Column {
Text(text = observeAsState.value)
TextField(
value = observeAsState.value,
onValueChange = { helloViewModel.onNameChanged(it) },
label = { Text(“Name”) }
)
}
}
异步操作
此处需要补充说明的是Compose的生命周期
Compose通过一系列Effect方法,实现生命周期函数
| Compose生命周期 | 说明 | 对应React |
| — | — | — |
| onActive | compose函数第一次被渲染到画面 | componentWillMount componentDidMount |
| onDispose | compose函数从画面上移除 | componentWillUnmount |
| onCommit | compose函数每次执行,画面重新渲染 | componentDidUpdate |
所以onCommit函数的使用类似于React的useEffect,支持可观察函数
@Suppress(“ComposableNaming”)
@Composable
/inline/
fun </reified/ V1> onCommit(
v1: V1,
/noinline/
callback: CommitScope.() -> Unit ) {
remember(v1) { PreCommitScopeImpl(callback) }
}
仅当v1发生变化时onCommit才会执行
举个例子使用异步操作
@Composable fun fetchImage(url: String): ImageAsset? {
// Holds our current image, and will be updated by the onCommit lambda below
var image by remember(url) { mutableStateOf<ImageAsset?>(null) }
onCommit(url) {
// This onCommit lambda will be invoked every time url changes
val listener = object : ExampleImageLoader.Listener() {
override fun onSuccess(bitmap: Bitmap) {
// When the image successfully loads, update our image state
image = bitmap.asImageAsset()
}
}
// Now execute the image loader
val imageLoader = ExampleImageLoader.get()
imageLoader.load(url).into(listener)
onDispose {
// If we leave composition, cancel any pending requests
imageLoader.cancel(listener)
}
}
// Return the state-backed image property. Any callers of this function
// will be recomposed once the image finishes loading
return image
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
学习分享
在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了
很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘
如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。
2021最新上万页的大厂面试真题
七大模块学习资料:如NDK模块开发、Android框架体系架构…
2021大厂面试真题:
只有系统,有方向的学习,才能在短时间内迅速提高自己的技术,只有不断地学习,不懈的努力才能拥有更好的技术,才能在互联网行业中立于不败之地。
片转存中…(img-Fm1jnO6Y-1711917868599)]
[外链图片转存中…(img-g4Mdms8G-1711917868600)]
[外链图片转存中…(img-WZOTh3Zt-1711917868600)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-EhgicPmy-1711917868600)]
学习分享
在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了
很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘
如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。
2021最新上万页的大厂面试真题
[外链图片转存中…(img-PhvOte2i-1711917868601)]
七大模块学习资料:如NDK模块开发、Android框架体系架构…
[外链图片转存中…(img-kBohPahN-1711917868601)]
2021大厂面试真题:
[外链图片转存中…(img-ynff9xAH-1711917868601)]
只有系统,有方向的学习,才能在短时间内迅速提高自己的技术,只有不断地学习,不懈的努力才能拥有更好的技术,才能在互联网行业中立于不败之地。