[Android WearOS] ScalingLazyColumn , Scaffold , Position Indicator 사용

JJAE WON·2023년 5월 20일
post-thumbnail

Android WearOS 에서는 웨어러블에서 사용이 가능한 WearableRecyclerView 를 지원해주고 있었다.

웨어의 UI를 Compose로 변화하면서 WearableRecyclerView 를 대응하는 ScalingLazyColumn 이 등장하게 되었다. 두둥

Jetpack Compose에서 RecyclerView 를 구현하는 방법

compose에서 RecyclerView를 구현하는 건 기존보다 훨씬 더 간단했다! 리싸이클러뷰를 구현할 때 셋트셋트로 구현해야 했던 Adpater 와 Holder를 구현하지 않아도 되기 때문이다.

Jetpack Compose에서 RecyclerView 를 구현하기 위해서는 LazyColumLazyRow 를 사용한다. 이름에서 알 수 있듯이 스크롤별 방향에 따른 두개의 component가 존재한다.

이 글에서는 LazyColum 이 주인공이 아니기 때문에 간단하게 살펴보자!

@Composable
fun composeRecycler(){
		val listState = rememberLazyListState() // 스크롤 위치와 항목의 변경사항에 반응하기 위한 상태 저장
		LazyColumn(
				state = listState,
				// 콘텐츠 가장자리에 padding 추가 하기
				contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp) ,

				// 항목 사이의 간격
				verticalArrangement = Arrangement.spacedBy(4.dp),
		){
		    // Add a single item
		    item {
		        Text(text = "First item")
		    }
		
		    // Add 5 items
		    items(5) { index ->
		        Text(text = "Item: $index")
		    }
		
		    // Add another single item
		    item {
		        Text(text = "Last item")
			    }
			}
}

스크롤 위치를 저장하기 위한 listState 로 LazyColum 에서 스크롤바나 위치 제어도 할 수 있다.

item 을 사용하여 단일 아이템을 추가하고 items 를 사용하여 람다 형식으로 항목들에 접근하여 추가할 수도 있다. 매개변수로 콘텐츠 가장자리의 패딩과 콘텐츠 사이의 간격을 조절한다.

이렇게 앱에서는 사용되어 왔었는데,,,!





WearOS의 작은 화면에 대응하기 위한ScalingLazyColumn

WearOS 의 특징은 app 화면보다 화면이 작아 제한적이라는 점이다.

그래서 Android에서는 Wear OS 용으로 LazyColum 클래스를 확장하여 맞춤형을 만들었다!

다양한 맞춤형 기능들이 존재하고 있다.

그중 가장 큰 기능인! 가독성에 도움을 주기 위해 스크롤이 위로 올라가는 항목에 페이드아웃 효과를 주는 것!


198ee8e8fa799f08

이렇게 기존의 LazyColum 을 WearOS에서 사용하게 되면 작은 화면에서 스크롤이 올라갈 때 짤리는 느낌이 들면서 UI적으로 조금 어색한 느낌이 들지만 ScalingLazyColum 에서는 자연스러운 스크롤 효과가 가능하다.

ScalingLazyColumn 사용예시

@Composable
fun UseScalingLazyList(){
    val listState = rememberScalingLazyListState()
    val contentModifier = Modifier
        .fillMaxWidth()
        .padding(bottom = 8.dp)
    val iconModifier = Modifier
        .size(24.dp)
        .wrapContentSize(align = Alignment.Center)

    ScalingLazyColumn(
        modifier = Modifier.fillMaxSize(),
        state = listState,
        autoCentering = AutoCenteringParams(0) // 화면 진입 시 가운데로 배치하
    ){
        item { ButtonExample(contentModifier, iconModifier) }
        item { TextExample(contentModifier) }
        item { CardExample(contentModifier, iconModifier) }
        item { ChipExample(contentModifier, iconModifier) }
        item { ToggleChipExample(contentModifier) }
    }
}

rememberScalingLazyListState() 는 위와 마찬가지로 ScalingLazyColumn 의 상태를 처리해주기 위해 사용된다.

ScalingLazyColum 은 시각적 효과를 보장하는 기본 설정을 제공하기 때문에 padding verticalArragnetment 와 같은 매개변수를 사용하지 않아도 된다.

그리고 첫번째 아이템으로는 ListHearder 를 사용하면 좋다. ListHearder로 지정된 아이템은 자동으로 autoCentering 속성이 부여된다. 커스텀을 위해 ListHearder 를 사용하지 않는다면 autoCentering 매개변수를 사용하여 수동으로 첫번째 항목에 충분한 패딩을 제공할 수 있다.



WearOs에서 Scaffold

Scaffold는 기존 앱에서 사용했었던 다양한 레이아웃들을 사용할 수 있는 발판으로 사용된다.

기존의 앱에서는 FAB 버튼이라던가 bottomBar , AppBar, SnackBar 와 같은 것들을 사용할 수 있었다.

하지만 WearOs 용 Scaffold 함수를 확인해보면 사용할 수 있는 매개변수가 많이 없다.

위에서 언급한 것들을 제공하지 않고 WearOS에 특화된 기능인 vignette timeText positionIndicator pageIndicator 를 제공하고 있다.

  • TimeText

image

Wear 는 시계를 보는 것이 주 목적이기 때문에 어디서든 시계를 표시할 것을 권장하고 있다. ( 대화상자와 같이 소비하는 시간이 짧을 경우 제외 )

해당 클래스를 사용하여 상단에 시계를 노출시킬 수 있다.

timeText = {
    TimeText(modifier = Modifier.scrollAway(listState))
}
  • Vignette

image

비네트 효과는 웨어러블 화면의 위쪽과 아래쪽을 흐리게 만드는데 사용되는 화면 장식이다.

vignette = {
    Vignette(vignettePosition = VignettePosition.TopAndBottom)
}
  • Position Indicator & Page Indicator
우리가 흔히 알고 있는 Wear용 Indicator 이다.


ScalingLazyColumn 에서의 스크롤바 - Position Indicator

Google Android WearOS 정책이 변경되었는데 전체 뷰가 스크롤되면 스크롤바를 표시해야 한다 라는 권장사항이 추가되었다.

워치에서는 볼륨상태와 스크롤의 상태를 알 수 있게 위에서 언급한 Position Indicator 를 사용하고 있다.

Psition Indicator는 위에서 언급한 대로 Scaffold 에서 사용된다. 하지만 스크롤을 표시해주는 기능을 하고 있으니 기존 우리의 생각으론

🤔 RecyclerView와 셋트이면.. LazyColum 에 사용되야 하는 것이 아닌가..?!

라고 생각할 수 있다!!

질문에 대한 대답은! Indicator 는 시계의 가운데에 위치해야 하기 때문에 Scaffold 에서 사용되야 하는 것이 맞다.

예를 들어 위처럼 플레이리스트 Text 요소 아래 ScalingLazyColum이 있을 수 있다. 그리고 다른것들이 겹쳐서 충분히 표시될 수 있다!! 위에 Text나 다른 요소들이 추가될 수도 있는 것..! 이럴 경우 ScalingLazyColum 레벨에 PositionIndicstor 가 추가된다면 위 그림처럼 가운데에 위치하지 않을 것이다..! 그렇기 때문에 시계의 전체 화면에 표시되어야 하기 때문에 Scaffold 레벨에서 사용되어져야 한다.



Position Indicator 사용 예시

Position Indicator는 ScalingLazyListState 이 아닌 ScrollStateLazyListState 과 같은 스크롤옵션에서도 사용할 수 있다. 우리는 ScalingLazyListState 스크롤 옵션을 사용하는 예시를 살펴 볼 것!

@Composable
fun PositionIndicator(
    scalingLazyListState: ScalingLazyListState,
    modifier: Modifier = Modifier,
    reverseDirection: Boolean = false
): Unit

위 함수는 스크롤옵션을 지정하여 사용하는 함수이다. 해당 매개변수들을 지정하여 사용할 수 있다.


@Composable
fun UseScalingLazyList() {
    val listState = rememberScalingLazyListState()
    val contentModifier = Modifier
        .fillMaxWidth()
        .padding(bottom = 8.dp)
    val iconModifier = Modifier
        .size(24.dp)
        .wrapContentSize(align = Alignment.Center)

    Scaffold(
        timeText = { TimeText(modifier = Modifier.scrollAway(listState)}, // 스크롤하면 시간 삭제 되는 구조) },
        vignette = { Vignette(vignettePosition = VignettePosition.TopAndBottom) },
        positionIndicator = {
            PositionIndicator(
                scalingLazyListState = listState,
            )
        }
    ) {
        ScalingLazyColumn(
            modifier = Modifier.fillMaxSize(),
            state = listState,
            autoCentering = AutoCenteringParams(0) // 화면 진입 시 가운데로 배치하
        ) {
            item { ButtonExample(contentModifier, iconModifier) }
            item { TextExample(contentModifier) }
            item { CardExample(contentModifier, iconModifier) }
            item { ChipExample(contentModifier, iconModifier) }
            item { ToggleChipExample(contentModifier) }
        }
    }
}

ScalingLazyColumn 와 같은 스크롤state 를 공유하여 Scaffold 에 있는 Position Indicator 에서 스크롤의 상태를 알 수 있다!!

스크롤의 상태를 알 기 때문에 스크롤이 될 때만 스크롤바가 생기고 아닐때 보여지지 않는 기능도 있다.

해당 스크롤바를 커스텀 할 수 있는 기능도 있는데 좀 더 살펴보고 글을 적어야겠다.



참고

Goole WearOS Compose 사용을 위한 CodeLab

Android WearOs 가이드라인

Android Developer - ScalingLazycolum

Position Indicator

profile
앱개발왕 찐천재가 되고싶다.

1개의 댓글

comment-user-thumbnail
2023년 10월 12일

안녕하세요. 좋은 글 감사합니다. !
"스크롤의 상태를 알 기 때문에 스크롤이 될 때만 스크롤바가 생기고 아닐때 보여지지 않는 기능도 있다."
라고 하셨는데요, 전 별다른건 하지 않았는데, 스크롤바가 항상 보여지진 않고 스크롤이 될때만 나오더라구요. 항상 스크롤바가 나오도록 하거나, 스크롤바의 visibility를 조정하기 위해선 어떻게 해야하는지도 도와주실 수 있으실까요? 공식 개발문서에 찾아봤는데도 찾기가 어렵네요 ㅠ

답글 달기