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()
}
}
}

Android Compose 入门,深入底层源码分析的更多相关文章

  1. Android Small插件化框架源码分析

    Android Small插件化框架源码分析 目录 概述 Small如何使用 插件加载流程 待改进的地方 一.概述 Small是一个写得非常简洁的插件化框架,工程源码位置:https://github ...

  2. List-LinkedList、set集合基础增强底层源码分析

    List-LinkedList 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 继上一章继续讲解,上章内容: List-ArreyLlist集合基础增强底层源码分析:https:// ...

  3. List-ArrayList集合基础增强底层源码分析

    List集合基础增强底层源码分析 作者:Stanley 罗昊 [转载请注明出处和署名,谢谢!] 集合分为三个系列,分别为:List.set.map List系列 特点:元素有序可重复 有序指的是元素的 ...

  4. LInkedList总结及部分底层源码分析

    LInkedList总结及部分底层源码分析 1. LinkedList的实现与继承关系 继承:AbstractSequentialList 抽象类 实现:List 接口 实现:Deque 接口 实现: ...

  5. Vector总结及部分底层源码分析

    Vector总结及部分底层源码分析 1. Vector继承的抽象类和实现的接口 Vector类实现的接口 List接口:里面定义了List集合的基本接口,Vector进行了实现 RandomAcces ...

  6. 【Android】Handler、Looper源码分析

    一.前言 源码分析使用的版本是 4.4.2_r1. Handler和Looper的入门知识以及讲解可以参考我的另外一篇博客:Android Handler机制 简单而言:Handler和Looper是 ...

  7. Android View事件分发-从源码分析

    View事件分发-从源码分析 学习自 <Android开发艺术探索> https://blog.csdn.net/qian520ao/article/details/78555397?lo ...

  8. Android线程间异步通信机制源码分析

    本文首先从整体架构分析了Android整个线程间消息传递机制,然后从源码角度介绍了各个组件的作用和完成的任务.文中并未对基础概念进行介绍,关于threadLacal和垃圾回收等等机制请自行研究. 基础 ...

  9. Android JobService的使用及源码分析

    Google在Android 5.0中引入JobScheduler来执行一些需要满足特定条件但不紧急的后台任务,APP利用JobScheduler来执行这些特殊的后台任务时来减少电量的消耗.本文首先介 ...

  10. JAVA ArrayList集合底层源码分析

    目录 ArrayList集合 一.ArrayList的注意事项 二. ArrayList 的底层操作机制源码分析(重点,难点.) 1.JDK8.0 2.JDK11.0 ArrayList集合 一.Ar ...

随机推荐

  1. 【Azure 应用服务】部署Azure Web App时,是否可以替换hostingstart.html文件呢?

    问题描述 当成功创建一个Web App时,通过高级工具(Kudu)可以查看 Web App的根目录(wwwroot)中有一个默认的文件(hostingstart.html).它就是应用服务的默认页面. ...

  2. 聚焦企业流程智能化发展新趋势,中国信通院2022 RPA创新产业峰会即将开启

    机器人流程自动化(Robotic Process Automation,RPA)是数字时代的重要劳动力之一,流程的自动化.智能化运行是企业释放运营能效.提升客户服务水平的重要路径. 近年来,各行业对R ...

  3. java基础 韩顺平老师的 面向对象(基础) 自己记的部分笔记

    194,对象内存布局 基本数据类型放在堆里面,字符串类型放在方法区. 栈:一般存放基本数据类型(局部变量) 堆:存放对象(Cat cat,数组等) 方法区:常量池(常量,比如字符串),类加载信息 19 ...

  4. audio currentTime 设置后,重置成0,解决方案(流文件-下载文件)

    audio currentTime 设置后,重置成0,解决方案 第一步-流文件-下载文件: 先查看你的mp3文件是 流文件,还是下载文件. 检测方式,就是放到浏览器回车.在线播放就是流文件,直接下载了 ...

  5. gitee 流水线 定时触发 不能用,不能白嫖了

    gitee 流水线 定时触发 不能用,不能白嫖了 白研究半天了,只好回去拿centos服务器 搞定时任务了

  6. 在Java中如何优雅的停止一个线程?可别再用Thread.stop()了!

    写在开头 经过上几篇博文的学习,我们知道在Java中可以通过new Thread().start()创建一个线程,那今天我们就来思考另外一个问题:线程的终止 自然终止有两种情况: 1. 线程的任务执行 ...

  7. 全栈的自我修养: 002使用@vue/cli进行vue.js环境搭建 (使用Vue,Spring Boot,Flask,Django 完成Vue前后端分离开发)

    全栈的自我修养: 使用@vue/cli进行vue.js环境搭建 Success, real success, is being willing to do the things that other ...

  8. Android webview只加载10%且出现白屏问题排查解决

    原文:Android webview只加载10%且出现白屏问题排查解决 - Stars-One的杂货小窝 问题 有一个主页面,布局里是包含的一个自定义Webview,并且注入了些原生的方法进去,供原生 ...

  9. AOSP下载且编译

    一.简介 AOSP:Android Open Source Project 二.环境要求 我们可以先了解官网(https://source.android.com/docs/setup/start/r ...

  10. 深度观察2024中国系统架构师大会(SACC)

    今年的中国系统架构师大会(SACC)在我所在的城市广州举办,很荣幸受邀参加.这次能接触到国内最优秀的架构师,学习他们的架构思想和行业经验.对我而言非常有意义. 大会分为上下午共4场,我参加了上午的多云 ...