Subject
AnimatedVisibility 을 통해 애니메이션 구현 시, 아래와 같은 에러가 출력되는 경우
can't be called in this context by implicit receiver. Use the explicit one if necessary
The Challenge
왜 이런 문제가 발생했을까?
코드를 먼저 보자
Card(
modifier = Modifier
.width(300.dp)
.wrapContentHeight(),
elevation = CardDefaults.cardElevation(0.dp),
shape = RoundedCornerShape(10.dp),
) {
Box() {
AnimatedVisibility( // Error!
visible = true,
enter = fadeIn(),
) {
...
Card는 ColumnScope
를 갖는다.그리고 AnimatedVisibility
는 Card를 통해 ColumnScope
를 Context로 전달받는다.
문제는 @DslMarker
이다. 이 아이는 어떤 역할을 하는 것일까?
우측 주소는 예시를 확인할 수 있는 사이트이다. https://pl.kotl.in/zoTq1_efU
@DslMarker // try commenting this line
annotation class FooDsl
@FooDsl
interface Root {
fun nested(init: Nested.() -> Unit)
}
@FooDsl
interface Nested {
var stuff: String?
}
fun makeRoot(init: Root.() -> Unit): Unit = TODO()
fun main() {
makeRoot {
nested {
nested { // 'fun nested(init: Nested.() -> Unit): Unit' can't be called in this context by implicit receiver. Use the explicit one if necessary
stuff = "stuff"
}
}
}
}
nested{} 안에 있는 nested{}에서 stuff를 접근하려 했기 때문에 에러가 났다. stuff는 Root를 리시버 형태로 컨텍스트를 전달받는데 내부 스코프에서 접근하려하니 @DslMarker 어노테이션 때문에 막혔다.
위와 같이 어노테이션을 통해 내부에서 외부 Context에 접근을 제한하는데 ColumnScope
는 @LayoutScopeMarker
라는 어노테이션이 달려있어 마찬가지로 외부 접근을 제한한다.
@LayoutScopeMarker
@Immutable
@JvmDefaultWithCompatibility
interface ColumnScope {
/**
* Size the element's height proportional to its [weight] relative to other weighted sibling
* elements in the [Column]. The parent will divide the vertical space remaining after measuring
* unweighted child elements and distribute it according to this weight.
* When [fill] is true, the element will be forced to occupy the whole height allocated to it.
* Otherwise, the element is allowed to be smaller - this will result in [Column] being smaller,
* as the unused allocated height will not be redistributed to other siblings.
*
* @param weight The proportional height to give to this element, as related to the total of
* all weighted siblings. Must be positive.
* @param fill When `true`, the element will occupy the whole height allocated.
*
* @sample androidx.compose.foundation.layout.samples.SimpleColumn
*/
@Stable
fun Modifier.weight(
/*@FloatRange(from = 0.0, fromInclusive = false)*/
weight: Float,
fill: Boolean = true
): Modifier
나와 같은 문제에 대해 stackoverflow에 질문이 올라왔고 누군가 Report도 올렸으나 개선의 의지는 아직 보이지 않는다.
다행히 우회책이 존재하는데 Composable 함수를 하나 더 만들어 Context 접근을 분리하는 방법이다.
이에 나는 울며겨자먹기로 AnimatedVisibility
를 사용하는 부분만 아래와 같이 분리하였다.
@Composable
fun LoadedImage(
painter: AsyncImagePainter,
onClick: () -> Unit
) {
AnimatedVisibility( // 함수가 호출되면 fadeIn()을 실행한다.
visible = true,
enter = fadeIn(),
exit = fadeOut()
) {
Image(
painter = painter,
contentDescription = null,
modifier = Modifier
.clickable { onClick() }
.fillMaxWidth()
.wrapContentHeight()
.animateContentSize(),
contentScale = ContentScale.FillWidth,
)
}
}
ⓒ 굿햄 2022. daryeou@gmail.com all rights reserved.
'Android > Compose' 카테고리의 다른 글
[Android] Compose를 활용한 Collapsing Toolbar Scaffold 제작기 (0) | 2023.07.23 |
---|---|
[안드로이드 Compose] 텍스트 중앙 정렬 맞추기 (1) | 2022.12.14 |
댓글