Android Compose 入门,深入底层源码分析

Android Compose 入门,深入底层源码分析

我是跟着AS官网学习的,但是官方的教程写的不是很详细.官网链接
首先创建一个Compose项目,目录结构是这样:
ui
-> theme
-> -> Color.kt
-> -> Theme.kt
-> -> Type.kt
MainActivity.kt
通过阅读源码,发现实际上还少了一个Shapes.kt,我手动添加了.

Type.kt

/** 
 * 存放组件的Style 
 * Typography全部是文字的属性
 * 点开Typography的代码,结构很简单.
 * 存了一些TextStyle,提供以下功能:
 * 主构造函数: 使用一些默认参数初始化各个TextStyle
 * copy: 复制一份
 * equals: 比较每一个TextStyle
 * hashCode: 计算hash,把每个TextStyle都计算进去.
 * fromToken: internal修饰,为Typography类增加拓展函数,根据传进来的enum,确认获取哪个TextStyle.
 * 在class外部还有一个对象:
 * LocalTypography: internal修饰,被MaterialTheme作为默认参数使用
 */ 
val Typography = Typography( 
 bodyLarge = TextStyle( 
 fontFamily = FontFamily.Default, 
 fontWeight = FontWeight.Normal, 
 fontSize = 16.sp, 
 lineHeight = 24.sp, 
 letterSpacing = 0.5.sp 
 )
)

Color.kt

/** 
 * 存放颜色值
 * darkColorScheme和lightColorScheme都属于ColorScheme 
 * 点开ColorScheme的代码,结构很简单.
 * 存了一些Color,提供以下功能:
 * 主构造函数: 颜色委托给mutableStateOf,使颜色值的变化可以被Compose观察.
 * copy: 复制一份
 * 剩下的是一些函数:
 * lightColorScheme: 提供默认的白天模式颜色
 * darkColorScheme: 提供默认的夜间模式颜色
 * ColorScheme.contentColorFor: 为ColorScheme类增加拓展函数,根据背景色使用对应的前景色,如果颜色不匹配,返回透明色.
 * contentColorFor: 提供一个函数,import这个函数来使用,如果颜色不匹配,返回黑色.
 * applyTonalElevation: internal修饰,为ColorScheme类增加拓展函数,返回新背景色,传入的背景色加上高度.
 * surfaceColorAtElevation: 为ColorScheme类增加拓展函数,计算不同高度的surface表面色调.
 * updateColorSchemeFrom: internal修饰,为ColorScheme类增加拓展函数,更新颜色,成本很高,但颜色委托给了mutableStateOf,忽略不变化的颜色值,提高运行效率.
 * fromToken: internal修饰,为ColorScheme类增加拓展函数,根据传进来的enum,确认获取哪个Color.
 * toColor: internal修饰,为ColorSchemeKeyTokens类增加拓展函数,将enum转换为对应的颜色,调用fromToken.
 * 在class外部还有两个对象:
 * LocalColorScheme: internal修饰,被MaterialTheme作为默认参数使用,默认使用lightColorScheme.
 * DisabledAlpha: internal修饰,禁用状态的前景色.比如禁用按钮的文字颜色.
 */ 
val Purple80 = Color(0xFFD0BCFF) 
val PurpleGrey80 = Color(0xFFCCC2DC) 
val Pink80 = Color(0xFFEFB8C8) 
val Purple40 = Color(0xFF6650a4) 
val PurpleGrey40 = Color(0xFF625b71) 
val Pink40 = Color(0xFF7D5260) 
//深色模式 
val DarkColorScheme = darkColorScheme( 
 primary = Purple80, 
 secondary = PurpleGrey80, 
 tertiary = Pink80 
) 
 
//浅色模式 
val LightColorScheme = lightColorScheme( 
 primary = Purple40, 
 secondary = PurpleGrey40, 
 tertiary = Pink40, 
)

Shapes.kt

/** 
 * 默认创建的项目里没有创建Shapes 
 * 这里也简单介绍一下 
 * 点开Shapes代码,结构很简单. 
 * 存放了一些形状,提供以下功能: 
 * 主构造函数: 存放一些CornerBasedShape 
 * CornerBasedShape基于角的形状,子类有: AbsoluteCutCornerShape,AbsoluteRoundedCornerShape,CutCornerShape,RoundedCornerShape. 
 * https://developer.android.com/reference/kotlin/androidx/compose/foundation/shape/CornerBasedShape * copy: 复制一份 
 * equals: 比较每个shape 
 * hashCode: 计算hash,把每个shape都计算进去. 
 * 类外部: 
 * ShapeDefaults: 提供CornerBasedShape的默认参数 
 * top,bottom,start,end: internal修饰,帮助组件获取Shape. 
 * fromToken: internal修饰,根据传入的enum,返回对应的Shape. 
 * toShape: internal修饰,为ShapeKeyTokens增加扩展函数,把enum转为Shape,调用fromToken. 
 * LocalShapes: internal修饰,被MaterialTheme作为默认参数使用,默认使用ShapeDefaults. 
 */val shapes = Shapes( 
 extraSmall = ShapeDefaults.ExtraSmall 
)

Theme.kt

/** 
 * 构建一个Theme用来使用 
 * 如果不用自己构建的theme,会使用默认的theme. 
 * Theme很简单,分为两部分. 
 * 由Compose托管的: 
 * 使用colorScheme,shapes,typography,content创建一个MaterialTheme. 
 * content使用这个MaterialTheme,并且这个MaterialTheme会递归传递给content内的@Composable修饰的函数. 
 * 非Compose托管的: 
 * 一些不属于View的,属于window的.如状态栏颜色,导航栏是否显示等. 
 * 然后是MaterialTheme的源码
 * MaterialTheme是一个@Composable修饰的函数,按照顺序拆解:
 * rememberedColorScheme,用来更新颜色.调用updateColorSchemeFrom.使用remember让currentComposer缓存colorScheme.copy()返回的对象,下次重组时继续使用该值,涉及的内容太多,这里不再深入.
 * rippleIndication,波纹动画,默认使用透明色,也就是没有波纹动画.
 * selectionColors,文字选中颜色,默认使用:rememberedColorScheme.primary
 * CompositionLocalProvider,一个@Composable修饰的函数,使用上面的参数构建一个ProvidedValue对象,调用currentComposer.startProviders保存这些对象,然后调用content绘制,绘制时会使用这些ProvidedValue对象,然后调用currentComposer.endProviders()终止记录.
 */ 
/** 
 * @param darkTheme 是否是深色模式 
 * @param dynamicColor 动态颜色 安卓12(api31) 新增,会基于系统壁纸的颜色使用对应的颜色,https://developer.android.com/develop/ui/views/theming/dynamic-colors 
 * @param content Composable代码块,使用colorScheme作为主题色 
 */ 
@Composable 
fun Study1Theme( 
 darkTheme: Boolean = isSystemInDarkTheme(), 
 dynamicColor: Boolean = true, 
 content: @Composable () -> Unit 
) { 
 //Material Design 需要的颜色 
 val colorScheme = when { 
 //使用动态颜色,跟随壁纸,只有大于api31才能使用 
 dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { 
 val context = LocalContext.current 
 if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) 
 } 
 
 darkTheme -> DarkColorScheme 
 else -> LightColorScheme 
 } 
 
 //获取View,@Composable的组合函数实际上是一个View 
 val view = LocalView.current 
 //不是编辑模式的情况下,设置一些参数 
 if (!view.isInEditMode) { 
 //window不是Compose管理的对象,需要用SideEffect来共享Compose状态,SideEffect保证每次重组后都会执行 
 SideEffect { 
 //设置status bar 颜色 
 val window = (view.context as Activity).window 
 window.statusBarColor = colorScheme.primary.toArgb() 
 WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme 
 } 
 } 
 
 //颜色,字体,代码块构建一个MaterialTheme对象,代码块的MaterialTheme对象会使用这个构建的对象 
 MaterialTheme( 
 colorScheme = colorScheme, 
 typography = typography, 
 shapes = shapes, 
 content = content 
 ) 
}

MainActivity.kt

这个没什么好说的,官方的教程说的很明白了.这里简单贴一下代码.

class MainActivity : ComponentActivity() { 
 override fun onCreate(savedInstanceState: Bundle?) { 
 super.onCreate(savedInstanceState) 
 //setContent是Kotlin的扩展函数,使用Compose创建窗口 
 setContent { 
 //Study1Theme在theme/Theme.kt里,生成MaterialTheme给整个代码块用 
 Study1Theme(dynamicColor = false) { 
 //使用一个@Composable函数来作为界面的入口 
 MyApp(Modifier.fillMaxSize()) 
 } 
 } } 
 
 //界面入口,用来复用函数 
 @Composable 
 fun MyApp(modifier: Modifier = Modifier){ 
 //Surface,一般显示组件的颜色,如卡片,表格,菜单的背景色 
 Surface( 
 //Modifier.fillMaxSize() 铺满父组件 
 modifier = modifier, 
 //使用Study1Theme里创建的MaterialTheme的colorScheme 
 //colorScheme现在有深色浅色两种模式,也可以添加更多风格. 
 color = MaterialTheme.colorScheme.primary 
 ) { 
 //Surface函数的最后一个参数是content: @Composable () -> Unit 
 //@Composable注解修饰的函数只能被同样@Composable修饰的函数调用 
 SayHello("Android") 
 } 
 } 
 
 //显示一个文本 
 @Composable 
 fun SayHello(name: String, modifier: Modifier = Modifier) { 
 Surface(color = MaterialTheme.colorScheme.primary) { 
 Text( 
 text = "Hello $name!", 
 modifier = modifier.padding(24.dp) 
 ) 
 } 
 } 
 
 //Preview可以预览无参或者有默认参数的Compose函数 
 @Preview(showBackground = true, name = "Say Hello Preview") 
 @Composable 
 fun SayHelloPreview(name: String = "Compose") { 
 Study1Theme(dynamicColor = false) { 
 MyApp() 
 } 
 } 
}
作者:laomuji666原文地址:https://www.cnblogs.com/laomuji666/p/18126525

%s 个评论

要回复文章请先登录注册