카탈로그 브라우저 만들기

TV에서 실행되는 미디어 앱은 사용자가 콘텐츠를 탐색하고 선택하며 콘텐츠 재생을 시작할 수 있도록 해야 합니다. 이러한 유형의 앱에서 콘텐츠 탐색 환경은 직관적이고 시각적으로 만족스러우며 흥미로워야 합니다.

카탈로그 브라우저는 여러 섹션으로 구성되는 경향이 있으며 각 섹션에는 미디어 콘텐츠 목록이 있습니다. 미디어 카탈로그의 섹션 예로는 재생목록, 추천 콘텐츠, 추천 카테고리가 있습니다.

그림 1. 일반적인 카탈로그 화면 사용자는 동영상 카탈로그 데이터를 탐색할 수 있습니다.

Compose for TV에서 제공하는 함수를 사용하여 앱의 미디어 카탈로그에서 음악이나 동영상을 탐색하는 사용자 인터페이스를 구현합니다.

카탈로그의 컴포저블 함수 만들기

디스플레이에 표시되는 모든 항목은 Compose for TV에서 구성 가능한 함수로 구현됩니다. 미디어 카탈로그 브라우저의 컴포저블 함수를 정의하는 것으로 시작합니다.

@Composable
fun CatalogBrowser(
    featuredContentList: List<Movie>,
    sectionList: List<Section>,
    modifier: Modifier = Modifier,
    onItemSelected: (Movie) -> Unit = {},
) {
    // ToDo: add implementation
}

CatalogBrowser는 미디어 카탈로그 브라우저를 구현하는 컴포저블 함수입니다. 이 함수는 다음 인수를 사용합니다.

  • 추천 콘텐츠 목록입니다.
  • 섹션 목록입니다.
  • Modifier 객체입니다.
  • 화면 전환을 트리거하는 콜백 함수입니다.

UI 요소 설정

TV용 Compose는 다수의 항목 (또는 길이를 알 수 없는 목록)을 표시하는 구성요소인 지연 목록을 제공합니다. LazyColumn를 호출하여 섹션을 세로로 배치합니다. LazyColumn는 항목 콘텐츠를 정의하는 DSL을 제공하는 LazyListScope.() -> Unit 블록을 제공합니다. 다음 예에서는 각 섹션이 섹션 간에 16dp 간격이 있는 세로 목록에 배치됩니다.

@Composable
fun CatalogBrowser(
    featuredContentList: List<Movie>,
    sectionList: List<Section>,
    modifier: Modifier = Modifier,
    onItemSelected: (Movie) -> Unit = {},
) {
    LazyColumn(
        modifier = modifier.fillMaxSize(),
        verticalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        items(sectionList.size) { index ->
            val section = sectionList[index]
            SectionRow(section, onItemSelected = onItemSelected)
        }
    }
}

이 예에서 구성 가능한 함수 SectionRow은 섹션을 표시하는 방법을 정의합니다. 다음 함수에서 LazyRow는 이 가로 버전의 LazyColumn가 제공된 DSL을 호출하여 LazyListScope.() -> Unit 블록으로 가로 목록을 정의하는 데 어떻게 유사하게 사용되는지 보여줍니다.

@Composable
fun SectionRow(
    section: Section,
    modifier: Modifier = Modifier,
    onItemSelected: (Movie) -> Unit = {},
) {
    Text(
        text = section.title,
        style = MaterialTheme.typography.headlineSmall,
    )
    MovieCatalog(
        section.movieList,
        onClick = { movie -> onItemSelected(movie) },
        modifier
    )
}

@Composable
fun MovieCatalog(
    movies: List<Movie>,
    onClick: (Movie) -> Unit,
    modifier: Modifier = Modifier,
) {
    LazyRow(
        modifier = modifier,
        horizontalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        items(movies.size) { index ->
            val movie = movies[index]
            MovieCard(
                movie = movie,
                onClick = { onClick(movie) }
            )
        }
    }
}

SectionRow 컴포저블에서 Text 구성요소가 사용됩니다. Material Design에 정의된 텍스트 및 기타 구성요소는 tv-material 라이브러리에서 제공됩니다 . MaterialTheme 객체를 참조하여 Material Design에 정의된 대로 텍스트 스타일을 변경할 수 있습니다. 이 객체는 tv-material 라이브러리에서도 제공됩니다. Card는 tv-material 라이브러리의 일부입니다. MovieCard는 각 영화 데이터가 카탈로그에서 렌더링되는 방식을 정의하며, 다음 스니펫과 같이 정의됩니다.

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MovieCard(
    movie: Movie,
    modifier: Modifier = Modifier,
    onClick: () -> Unit = {}
) {
    Card(
        modifier = modifier,
        onClick = onClick
    ) {
        AsyncImage(
            model = movie.thumbnailUrl,
            contentDescription = movie.title,
        )
    }
}

앞에서 설명한 예시에서는 모든 영화가 동일하게 표시됩니다. 면적이 같고 시각적 차이가 없습니다. Carousel를 사용하여 일부를 강조 표시할 수 있습니다.

캐러셀은 슬라이드, 페이드 또는 뷰로 이동할 수 있는 항목 집합에 정보를 표시합니다. 이 구성요소를 사용하여 새로 제공되는 영화나 TV 프로그램의 새 에피소드와 같은 추천 콘텐츠를 강조 표시합니다.

Carousel에서는 최소한 캐러셀에 있는 항목 수와 각 항목을 그리는 방법을 지정해야 합니다. 첫 번째는 itemCount로 지정할 수 있습니다. 두 번째는 람다로 전달할 수 있습니다. 표시된 항목의 색인 번호가 람다에 제공됩니다. 지정된 색인 값으로 표시된 항목을 확인할 수 있습니다.

Carousel는 LazyColumn과 같은 지연 목록의 항목일 수 있습니다. 다음 스니펫은 모든 SectionRow 컴포저블 위에 있는 FeaturedCarousel 컴포저블을 보여줍니다.