CompositionLocal
https://developer.android.com/jetpack/compose/compositionlocal?hl=ko
Composition : 구성요소들, 구성
Local : 지역의, (인체의) 일부에 대한
CompositionLocal 지역의 구성요소들 입니다.
Compose 에서 사용하는 예
- MaterialTheme (내부 구성)
- LocalColors
- LocalContentColor
- LocalContext
- etc....
https://play.google.com/store/apps/details?id=com.danchoo.tagalbum&hl=ko
UI 트리를 통해 데이터 흐름이 발생하는 암시적 방법으로 사용할 수 있는 트리 범위의 명명된 객체를 만들 수 있습니다.
Compose 는 트리형태의 노드 구성을 가지고 있습니다.
상위 노드에서 하위 노드까지 데이터를 전달하기는 사실상 어려울 수 있습니다.
그렇기 때문에 CompositionLocal 을 사용하여 객체를 사용 하는 것을 제공 합니다.
Compose 에서 가장 많이 사용하는 Theme
theme 도 내부적으로 CompostionLocal 으로 구성되어 있습니다.
@Composable
fun MaterialTheme(
colors: Colors = MaterialTheme.colors,
typography: Typography = MaterialTheme.typography,
shapes: Shapes = MaterialTheme.shapes,
content: @Composable () -> Unit
) {
val rememberedColors = remember {
// Explicitly creating a new object here so we don't mutate the initial [colors]
// provided, and overwrite the values set in it.
colors.copy()
}.apply { updateColorsFrom(colors) }
val rippleIndication = rememberRipple()
val selectionColors = rememberTextSelectionColors(rememberedColors)
CompositionLocalProvider(
LocalColors provides rememberedColors,
LocalContentAlpha provides ContentAlpha.high,
LocalIndication provides rippleIndication,
LocalRippleTheme provides MaterialRippleTheme,
LocalShapes provides shapes,
LocalTextSelectionColors provides selectionColors,
LocalTypography provides typography
) {
ProvideTextStyle(value = typography.body1) {
PlatformMaterialTheme(content)
}
}
}
위의 코드에서 LocalColor, LocalContentAlpha, LocalIndication, LocalRippleTheme 등 여러가지 CompositionLocal 을 사용합니다.
MaterialTheme 의 content block 안에 있는 Compose 객체들은 MatrialTheme 의 영향을 받게 됩니다.
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
// GalleryScreen은 MaterialTheme 의 영향을 받습니다.
GalleryScreen()
}
}
}
}
사용자가 CompositionLocalProvider 함수를 사용하여
CompositionLocal의 데이터를 재정의 혹은 다른 CompositionLocal을 추가 할수 있습니다.
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// 새로 정의한 Theme
GlideImageTheme {
// 사용자가 정의한 LocalImageLoader 를 CompositionLocalProvider 로 적용
CompositionLocalProvider(LocalImageLoader provides GlideAppImageLoaderImpl()) {
GalleryScreen()
}
}
}
}
}
위의 코드는 CompositionLocalProvider를 사용하여 새로 정의한 Theme와 CompositionLocal을 적용하는 코드 입니다.
CompositionLocalProvider 내부 구현
@Composable
@OptIn(InternalComposeApi::class)
fun CompositionLocalProvider(vararg values: ProvidedValue<*>, content: @Composable () -> Unit) {
currentComposer.startProviders(values)
content()
currentComposer.endProviders()
}
특이하게 TextStyle은 CompositionLocalProvicer로 적용하면 안됩니다.
아래와 같이 ProvideTextStyle 를 사용하여 적용 해야 합니다.
ProvideTextStyle(value = typography.body1) {
PlatformMaterialTheme(content)
}
사실상 위의 설명으로만 보면 이걸 어떻게 구현 하는지 잘 모릅니다.
저도 그랬고........
설명은 제 블로그보다 다른 블로그 혹은 Devloper가 낫기 때문에 여기서 때려치우겠습니다!!!!
https://smartstore.naver.com/happysiso
하지만 어떻게 적용해야 하는지 샘플코드를 작성했습니다.
@Composable
fun BackTopAppBar(
modifier: Modifier = Modifier,
title: @Composable () -> Unit,
onClickBack: () -> Unit = {},
actions: @Composable RowScope.() -> Unit = {},
backgroundColor: Color = MaterialTheme.colors.primarySurface,
contentColor: Color = contentColorFor(backgroundColor)
) {
TopAppBar(
modifier = modifier,
contentColor = contentColor,
navigationIcon = {
IconButton(
imageVector = Icons.Filled.ArrowBack,
onClick = onClickBack
)
},
title = {
ProvideTextStyle(value = MaterialTheme.typography.subtitle1) {
title()
}
},
actions = {
ProvideTextStyle(value = MaterialTheme.typography.subtitle2) {
actions()
}
}
)
}
화면에 BackButton 이 많이 사용되기 때문에 따로 Composable로 생성 하여 사용하고 있습니다.
title과 actions 는 유동적으로 사용하기 위하여 @Composable () -> Unit (Higher order function - 고차함수) 를 사용했습니다.
(스터디용 토이 프로젝트- 완성되면 store 에 올릴 예정 입니다.ㅎㅎ - 디자이너가 없는게 함정....ㅠㅠ 아는 분한테 부탁 해야 할것 같은데...)
*고차 함수 : https://ko.wikipedia.org/wiki/%EA%B3%A0%EC%B0%A8_%ED%95%A8%EC%88%98
* koliin page : https://kotlinlang.org/docs/lambdas.html
ProvideTextStyle을 사용하여 TextStyle을 변경 했습니다.
하기와 같이 TopAppbar가 필요할때 BackTopAppBar 로 사용을 하게 된다면
title block 에 들어가는 Text는 모두 MatrialTheme.typography.subtitle1 이 적용되게 됩니다.
암시적으로 subtitle1 이 적용되도록 구현되었습니다.
Scaffold(
modifier = modifier.fillMaxSize(),
topBar = {
BackTopAppBar(
title = {
// Text Style 은 MaterialTheme.typography.subtitle1 이 적용된다
Text(text = "Title")
},
actions = {
// Text Style 은 MaterialTheme.typography.subtitle2 가 적용된다
Text(text = "TextButton")
}
)
}
) {
// content 내용
}
또한 하기와 같이 다른 CompositionLocal과 동시 적용이 가능 합니다.
fun BackTopAppBar(
modifier: Modifier = Modifier,
title: @Composable () -> Unit,
onClickBack: () -> Unit = {},
actions: @Composable RowScope.() -> Unit = {},
backgroundColor: Color = MaterialTheme.colors.primarySurface,
contentColor: Color = contentColorFor(backgroundColor)
) {
TopAppBar(
modifier = modifier,
contentColor = contentColor,
navigationIcon = {
IconButton(
imageVector = Icons.Filled.ArrowBack,
onClick = onClickBack
)
},
title = {
// LocalContentAlpha, LocalContentColor 적용
CompositionLocalProvider(
LocalContentAlpha provides ContentAlpha.medium,
LocalContentColor provides Color.Red
) {
// TextStyle 적용
ProvideTextStyle(value = MaterialTheme.typography.subtitle1) {
title()
}
}
},
actions = {
ProvideTextStyle(value = MaterialTheme.typography.subtitle2) {
actions()
}
}
)
}
하기 코드는 CompositionLocal, Hilt, Glide, Compose 를 사용하여 이미지를 로드하는 것을 공부하는 겸 구현 해봤습니다.
코드에 대한 자세한 설명은 다른 포스팅에서 진행 하겠습니다. (구조는 Coil 을 참고하여 만들었습니다.)
sample code로 갤러리 리스트를 보여주도록 했습니다. (물론 버그가 많습니다. webp 적용을 하지 않았습니다 - 재생 안됨....)
github : https://github.com/danchoo21/compose-glide-image
https://myseong.tistory.com/46
'Android > Kotlin' 카테고리의 다른 글
[Android] Compose Dialog Full Screen (Full Width Screen) (0) | 2023.05.10 |
---|---|
[Android] Compose MVI, MVVM+ (MvRx) (0) | 2022.08.06 |
[Android] Compose lifecycle (0) | 2022.03.26 |
[Android] Compose State, Statefull, Stateless, State Hoisting (0) | 2022.03.26 |
[Android] Compose 와 선언형 UI (0) | 2022.03.26 |
댓글