分析第一个程序
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeTheme {
// A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
Greeting("Android")
}
}
}
}
}
复制代码
我们可以看到,compose的入口还是Activity,但和之前不同的是,onCreate方法中的setContentView方法不见了,取而代之的是setContent。那么怎么显示布局呢?我们点到setContent的源码看看里面怎么做的:
public fun ComponentActivity.setContent(
parent: CompositionContext? = null,
content: @Composable () -> Unit
) {
val existingComposeView = window.decorView
.findViewById<ViewGroup>(android.R.id.content)
.getChildAt(0) as? ComposeView
if (existingComposeView != null) with(existingComposeView) {
setParentCompositionContext(parent)
setContent(content)
} else ComposeView(this).apply {
// Set content and parent **before** setContentView
// to have ComposeView create the composition on attach
setParentCompositionContext(parent)
setContent(content)
// Set the view tree owners before setting the content view so that the inflation process
// and attach listeners will see them already present
setOwners()
setContentView(this, DefaultActivityContentLayoutParams)
}
}
复制代码
首先这个方法是ComponentActivity的一个扩展方法,而上面自动生成的MainActivity也继承自ComponentActivity。下面通过Activity中window的decorView来找到根布局,再获取根布局的第0个子布局并将其强制转化为ComposeView。但现在我们并没有设置,所以existingComposeView为NULL,遇事会走进else分支创建一个新的ComposeView,然后在setContentView之前设置内容和父项,以使ComposeView创建合成,最后就会调用setContentView。在setContent方法中,第一个参数为Compose中的父控件,用于调度,第二个参数是一个含有Composable lambda参数的Composable函数。
setContent中包裹着ComposeTheme,他是Compose的主题,包裹着Surface并设定了页面的背景颜色,Surface中包裹着的Greeting就是显示在页面上的控件,即页面展示的Hellow World控件。
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
复制代码
Greeting是一个方法,也叫可组合函数,因为在Compose中可以使用的控件。使用Compose控件需要注意以下几点:
1.此函数带有@Composable注解。所有可组合函数都必须带有此注解,该注解告知Compose编 译器:这个函数旨在将数据转换成界面。
2.可组合函数可以接收参数,这些参数可以让应用程序逻辑描述页面,比如上面的例子中Greeing方法接收String类型的参数,可直接显示在界面中。
3.可组合函数没有返回值,发出界面的Compose函数不需要返回任何内容,
4.可组合函数在描述界面中的时候没有任何副作用,比如修改属性或全局变量等。
使用Preview
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
ComposeTheme {
Greeting("Android")
}
}
复制代码
我们在右侧的Split可以看到预览效果
试着把方法参数“Android”修改成“My Android”
如果修改代码后预览没有及时更新,则手动点击左上角的刷新按钮即可刷新。
Preview使用方法有很多,我们可以看看这个注解类的代码:
@Repeatable
annotation class Preview(
val name: String = "",
val group: String = "",
@IntRange(from = 1) val apiLevel: Int = -1,
// TODO(mount): Make this Dp when they are inline classes
val widthDp: Int = -1,
// TODO(mount): Make this Dp when they are inline classes
val heightDp: Int = -1,
val locale: String = "",
@FloatRange(from = 0.01) val fontScale: Float = 1f,
val showSystemUi: Boolean = false,
val showBackground: Boolean = false,
val backgroundColor: Long = 0,
@UiMode val uiMode: Int = 0,
@Device val device: String = Devices.DEFAULT
)
复制代码
我们试着更改预览态的宽高,我们可以在右侧预览态看到效果:
@Preview(showBackground = true, widthDp = 100, heightDp = 150)
@Composable
fun DefaultPreview() {
ComposeTheme {
Greeting("My Android")
}
}
复制代码
其他的属性大家可以试着去验证下。