이제 식물 설명을 마이그레이션해 해보자. fragment_plant_detail.xml의 코드에는 화면에 표시할 텍스트를 XML에 알려주기 위해 app:renderHtml=”@{viewModel.plant.description}”이 있는 TextView가 있다. renderHtml은 PlantDetailBindingAdapters.kt 파일에서 찾을 수 있는 바인딩 어댑터다. 구현은 HtmlCompat.fromHtml을 사용하여 TextView의 텍스트를 설정한다.

그러나 컴포즈는 현재 Spanned 클래스를 지원하지 않고, HTML 형식의 텍스트를 표시하지 않는다. 따라서 이 한계를 우회하려면, 컴포즈 코드의 View 시스템에서 TextView를 사용해야 한다.

컴포즈는 아직 HTML 코드를 렌더링할 수 없으므로, AndroidView API를 사용하여 정확히 이를 수행하도록 프로그래밍 방식으로 TextView를 생성해야 한다.

AndroidView는 View를 매개변수로 사용하고, View가 전개되었을 때 콜백을 제공한다.

Note: AndroidView는 프로그래밍 방식으로 생성된 View를 사용한다. XML 파일을 삽입하려는 경우 androidx.compose.ui:ui-viewbinding 라이브러리에서 AndroidViewBinding API로 View Binding을 사용하여 삽입할 수 있다

새 PlantDescription 컴포저블을 만들어 이를 수행해보자. 이 컴포저블은 방금 람다에서 기억한(remember 함수로 컴포지션 트리 내부에 저장한) TextView와 함께 AndroidView를 호출한다. factory 콜백에서 주어진 Context를 사용하여 HTML 상호 작용에 반응하는 TextView를 초기화한다. 그리고 업데이트 콜백에서 기억된 HTML 형식의 description으로 텍스트를 설정한다.

PlantDetailDescription.kt

@Composable
private fun PlantDescription(description: String) {
    // HTML 형식의 description을 내부에 저장한다. 새로운 description이 들어오면 람다식을 재실행한다.
    val htmlDescription = remember(description) {
        HtmlCompat.fromHtml(description, HtmlCompat.FROM_HTML_MODE_COMPACT)
    }

    // 화면상에 TextView를 표시하고 전개 될 때 HTML description을 업데이트 한다.
    // htmlDescription을 업데이트 하는 것은 AndroidView를 재구성하도록 만들고, 텍스트를 업데이트 시킨다.
    AndroidView(
        factory = { context ->
            TextView(context).apply {
                movementMethod = LinkMovementMethod.getInstance()
            }
        },
        update = {
            it.text = htmlDescription
        }
    )
}

@Preview
@Composable
private fun PlantDescriptionPreview() {
    MaterialTheme {
        PlantDescription("HTML<br><br>description")
    }
}

미리보기로 보면 다음과 같다.

95d8ca1832c1ef26.png


htmlDescription은 매개변수로 전달된 주어진 설명에 대한 HTML description을 내부에 저장한다. description 매개변수가 변경되면 메모리 내부의 htmlDescription 코드가 다시 실행된다.

마찬가지로, htmlDescription이 변경되면, AndroidView 업데이트 콜백은 재구성(recompose)한다. 콜백 내부에서 읽은 모든 상태는 재구성을 유발시키는 요소가 된다.

PlantDetailContent 컴포저블에 PlantDescription을 추가하고, HTML description도 표시하도록 미리보기 코드를 변경해 보자.

PlantDetailDescription.kt

@Composable
fun PlantDetailContent(plant: Plant) {
    Surface {
        Column(Modifier.padding(dimensionResource(R.dimen.margin_normal))) {
            PlantName(plant.name)
            PlantWatering(plant.wateringInterval)
            PlantDescription(plant.description)
        }
    }
}

@Preview
@Composable
private fun PlantDetailContentPreview() {
    val plant = Plant("id", "Apple", "HTML<br><br>description", 3, 30, "")
    MaterialTheme {
        PlantDetailContent(plant)
    }
}

미리보기로 보면 다음과 같다.

aa43efe444af4f75.png

여기까지, 원본 ConstraintLayout 내의 모든 콘텐츠를 컴포즈로 마이그레이션 했다. 앱을 실행하여 예상대로 작동하는지 확인할 수 있다.

e2f5c3ec20d4966f.gif

카테고리: Compose

0개의 댓글

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.