Jetpack Compose - 一文了解清楚神秘的CompositionLocal

Compose中CompositionLocal是一种用于在Compose组件树中传递和共享数据的机制,它允许在组件树中向下传递并且在任何地方可以访问此数据。本文主要从简介、简单使用CompositionLocal、自定义CompositionLocal和实现换肤功能四个模块介绍。

简介

文章开头我们知道了CompositionLocal是用于组件树中传递和共享数据的作用,Compose原生也有很多地方使用了它,比如LocalContextLocalContentColor等都是采用CompositionLocal的方式进行数据的共享。

在没有使用CompositionLocal之前,我们传递数据通常都是从组件树的上级一层一层的传递到下级,这样数据的传递就会呈显示传递;如果使用CompositionLocal之后,只需要在顶层方法中定义好数据,然后组件树中任何层级都可以获取和更改它的数值,这样在数据的传递中它是呈隐式传递,这样在维护代码和阅读代码的过程中都是提供了良好的可读性。

简单使用CompositionLocal

为了了解CompositionLocal的机制,我么首先通过自带的LocalContentColor来学习下如何使用和局部修改它的值

LocalContentColor是Compose定义的一个CompositionLocal对象,它是用于传递和共享当前主题下内容的颜色值

val LocalContentColor = compositionLocalOf { Color.Black }

它采用的是compositionLocalOf的方式来定义,具体使用看下方代码

Snap12.png

这里我们用三个Text来展示初始颜色值和提供局部颜色之后的区别,通过CompositionLocalProvider方法来提供局部的值改变,它接收两个参数,分别为valuecontentvalue就是我们提供的颜色值,然后在content中组件的颜色就会获取到我们提供的颜色。

LocalContentColor provides Color.Blue是提供颜色值的方法,providers是一个infix修饰的方法,此写法等同于LocalContentColor.provides(Color.Blue),下面我们看看具体实现的效果:

通过截图可以看出,最上面字体颜色就是系统提供的原始黑色,后面两行字体颜色分别是我们局部修改LocalContentColor的颜色值,最下面那行文字依旧是系统提供的原始颜色,它不收CompositionLocalProvider影响。

自定义CompositionLocal

Compose为我么提供了两种创建CompositionLocal的方式,分别为:

compositionLocalOf{}:使用这种方式定义的CompositionLocal在值更改的时候,只会重组CompositionLocalProvider{ content()}content读取current的地方;

staticCompositionLocalOf{}:与compositionLocalOf不一样,更改该值会导致CompositionLocalProvider{ content() }contentLambda被整体重组,而不仅仅是content中读取current值的地方。

从上面可以看出static的方式在值更改后影响更大,一般static方式更适用全局定义的某个数据或者标志,Compose中LocalLifecycleOwner就是采用的static的方式

接着我们来创建自己维护的一个CompositionLocal,在简单使用环节我们了解了官方提供的LocalContentColor机制之后,我们先仿照它来自己写一个CompositionLocal,也是用于传递和共享字体颜色使用。

首先定义自己的CompositionLocal,并且设置默认颜色为Green

然后将上面代码稍微修改一下,修改如下:

这里注意的一个点就是需要显示的设置Text的字体颜色,如果不设置的话还是默认使用系统主题的颜色,然后在CompositionLocalProvider中将LocalContentColor修改为我们自己的CustomColor,再来看下具体效果

从截图中可以看到我们自定义的颜色也是生效了,而且局部修改的情况下,颜色值也是正确替换。

本小节的最后我们再来看下compositionLocalOf{}staticCompositionLocalOf{}的区别,通过下面的例子可直观的了解二者对于重组的不同之处。

首先分别定义compositionLocalOf{}staticCompositionLocalOf{}的对象

然后定义三个方块,中间那个方块的背景颜色引用CompositionLocal对应的颜色值,每个方块正上方添加一个文本,此文本的文字初始一致,但是在界面组合完成之后更改,再更改CompositionLocal值之后,观察三个颜色和上方文本是否有变化

方块的具体代码如下:

接着编码具体切换代码

这里先体验的是NormalComposotionLocalOf{}方式,先看此方式的效果

然后将NormalCompositionLocal替换成StaticCompositionLocal的方式,再看看其实现的效果

通过上面两个GIF可以看出,在compositionLocalOf的方式下,之后中间方块发生了重组,上方的文字从init变成了recompose,而staticCompositionLocal的方式,所有方块都发生了重组,方块的上方文字都发生了变化,这个例子就可以直观的表现出二者对于重组的不同之处。

实现动态换肤功能

在具体编码之前,我们先理一下换肤的几个步骤:

  1. 通过枚举定义我们需要的主题皮肤类型
  2. 定义一个管理类来保存当前主题皮肤的值(在实际项目中还需要保存到本地,下次启动时需要获取到切换的具体值)
  3. 定义主题颜色,有几个主题就需要定义对应几个颜色
  4. 通过CompositionLocal引用当前主题对应的具体颜色,向全局传递当前主题类型,并且在切换皮肤的时候通知全局更换对应的颜色
  5. 在组件中引用CompositionLocal的值,这样就可以在切换主题时动态改变组件引用的颜色值。

了解了具体思路之后,下面我们就开始实际的编码过程。

首先定义主题皮肤类型

然后定义一个静态类,里面通过State保存当前的主题类型,默认为白色主题

接着开始定义四种主题各自对应的具体颜色

现在我们就可以通过CompositionLocal来定义App全局的主题颜色了,默认采用白色主题颜色,注意这里采用的是staticCompositionLocalOf{}方式,因为切换主题我们大多数组件都是需要来重组改变颜色的。

最后一步,自定义一个主题,在主题外层通过CompositionLocalProvider提供AppColors,这样就可以通过LocalThemeColor在具体的组件中引用对应的颜色

上面代码有几点需要注意:

  • CompositionLocalProvider之前我们需要根据ThemeManager中当前主题获取到对应的颜色
  • 无论是组件的背景色还是文字的颜色都直接使用LocalThemeColor.current.**
  • 切换主题时,直接调用ThemeManager.currentThemeType,修改其值即可完成主题切换

最后我们来看下具体的效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ccSsixDx-1691394158725)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1645e5c2fc3d44da890cf3f50ac204ae~tplv-k3u1fbpfcp-jj-mark:3024:0:0:0:q75.image)]

背景色和文字的颜色都是跟随主题变换随之切换的,状态栏和导航栏的颜色也可以跟随主题变换而改变哦~

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集

在这里插入图片描述
二、源码解析合集
在这里插入图片描述

三、开源框架合集
在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值