지연 리스트 튜토리얼

손현수·2024년 3월 28일

안드로이드 Compose

목록 보기
14/25

Row, Column을 활용하여 리스트를 만드는 것이 가능하나, 대부분의 상황에서 사용하는 것은 LazyRow, LazyColumn이다. 긴 리스트를 효율적으로 표시할 수 있고 스티키 헤더, 스크롤 위치 변경에 대응하는 등 다양한 기능을 제공하기 때문이다.

이미지 로딩 처리하기(Coil 라이브러리)

차량의 제조사와 이름을 담고 있는 문자열 배열과 함께 제조사의 로고 이미지를 표시하려면 로고 이미지들을 웹 서버로부터 다운로드받고 Image 컴포저블로 렌더링할 수 있다. 이때 이미지는 비동기적으로 다운로드되어 앱을 방해하지 말아야 한다.

이 작업을 하기 위해서는 이미지 로딩 라이브러리인 Coil을 사용해야 한다. Coil 라이브러리를 사용하면 특정 URL에 접근하여 이미지를 다운로드받고 앱에 렌더링하는 것이 가능하다. Coil을 사용하기 위해 다음 코드를 build.gradle에 추가한다.

implementation("io.coil-kt:coil-compose:1.3.2")

다음으로 이미지를 다운로드하고 Image 컴포넌트를 이용해 다운로드한 이미지를 표시하는 컴포저블 함수를 추가한다.

@Composable
fun ImageLoader(item: String) {
    val url = "https://www.ebookfrenzy.com/book_examples/car_logos" +
            item.substringBefore(" ") + "_logo.png"
}
  • 위의 코드는 substringBefore() 함수를 통해 "제조사 차량이름" 형태의 문자열에서 제조사를 얻은 뒤, 이를 이용해 완전한 이미지 URL을 구성한다.
  • 획득한 이미지의 경로는 다음과 같이 사용한다.
@Composable
fun ImageLoader(item: String) {
    val url = "https://www.ebookfrenzy.com/book_examples/car_logos" +
            item.substringBefore(" ") + "_logo.png"

    Image(
        painter = rememberImagePainter(url),
        contentDescription = "car image",
        contentScale = ContentScale.Fit,
        modifier = Modifier.size(75.dp)
    )
}
  • 위의 코드는 Coil의 rememberImagePainter() 함수에 이미지 URL을 전달하여 이미지 페인터를 요청한다. 해당 URL에서 이미지를 다운로드받기 위해서는 manifests에 인터넷 접근 권한을 추가해야 한다.
  • 그 후에 에뮬레이터를 실행하면 다음과 같이 화면이 렌더링된다.

리스트 아이템 컴포저블 디자인하기

하나의 Row에 이미지와 문자열을 표시하는 컴포저블을 만들어본다. elevation 효과와 둥근 모서리와 같은 커스터마이징을 위해 Row를 Card 안에 배치한다.

@Composable
fun MainScreen(itemArray: Array<out String>) {
    MyCardListItem("Buick Roadmaster")
}

@OptIn(ExperimentalCoilApi::class)
@Composable
fun ImageLoader(item: String) {
    val url = "https://www.ebookfrenzy.com/book_examples/car_logos/" +
            item.substringBefore(" ") + "_logo.png"

    Image(
        painter = rememberImagePainter(url),
        contentDescription = "car image",
        contentScale = ContentScale.Fit,
        modifier = Modifier.size(75.dp)
    )
}

@Composable
fun MyCardListItem(item: String) {
    Card(
        modifier = Modifier
            .padding(8.dp)
            .fillMaxWidth(),
        shape = RoundedCornerShape(10.dp),
        elevation = CardDefaults.cardElevation(
            defaultElevation = 5.dp
        )
    ) {
        Row(verticalAlignment = Alignment.CenterVertically) {
            ImageLoader(item = item)
            Spacer(modifier = Modifier.width(8.dp))
            Text(
                text = item,
                style = MaterialTheme.typography.headlineSmall,
                modifier = Modifier.padding(8.dp)
            )
        }
    }
}
  • 위의 코드를 실행하면 다음과 같은 화면이 렌더링된다.

지연 리스트 만들기

이제는 리스트 전체의 아이템을 렌더링하도록 한다.

@Composable
fun MainScreen(itemArray: Array<out String>) {
    LazyColumn() {
        items(itemArray) { model ->
            MyCardListItem(item = model)
        }
    }
}
  • MainScreen() 함수를 위와 같이 수정하여 itemArray에 있는 아이템들을 하나씩 렌더링할 수 있다. 위 코드를 실행하면 다음과 같은 화면이 렌더링된다.

리스트 아이템 클릭하기

리스트의 아이템을 클릭했을 때 토스트 메시지가 표시되도록 코드를 수정한다. 이를 위해 클릭 이벤트 핸들러 콜백 함수를 추가한다.
먼저 MainScreen에서 이벤트 핸들러 함수를 정의한다.

@Composable
fun MainScreen(itemArray: Array<out String>) {
    val context = LocalContext.current
    val onListItemClick = { text: String ->
        Toast.makeText(
            context,
            text,
            Toast.LENGTH_SHORT
        ).show()
    }

    LazyColumn() {
        items(itemArray) { model ->
            MyCardListItem(item = model, onItemClick = onListItemClick)
        }
    }
}
  • 클릭된 아이템의 텍스트를 가져와서 토스트 메시지로 표시하는 함수를 정의하고 MyCardListItem 컴포저블에 파라미터로 함수를 전달한다.
  • 그 다음으로는 파라미터로 전달받은 이벤트 핸들러 함수를 사용하여 Card 컴포저블을 클릭가능하게 만든다.
@Composable
fun MyCardListItem(item: String, onItemClick: (String) -> (Unit)) {
    Card(
        modifier = Modifier
            .padding(8.dp)
            .fillMaxWidth()
            .clickable {onItemClick(item)},
        shape = RoundedCornerShape(10.dp),
        elevation = CardDefaults.cardElevation(
            defaultElevation = 5.dp
        )
    ) {
        Row(verticalAlignment = Alignment.CenterVertically) {
            ImageLoader(item = item)
            Spacer(modifier = Modifier.width(8.dp))
            Text(
                text = item,
                style = MaterialTheme.typography.headlineSmall,
                modifier = Modifier.padding(8.dp)
            )
        }
    }
}
  • Card의 모디파이어를 활용하여 Card를 클릭가능하게 만들고 이벤트 핸들러 함수를 전달하였다. 클릭된 아이템의 이름을 핸들러 함수의 파라미터로 전달하여 토스트 메시지로 표시되도록 한다.

위 코드를 실행하면 다음과 같은 화면을 확인할 수 있다.

profile
안녕하세요.

0개의 댓글