이 짧고 실용적인 기사에서는 Jetpack Compose에서 UI 이벤트를 처리하는 방법에 대해 설명합니다.
이전 시스템에서는 OnClickListeners 및 기타 인터페이스를 사용했습니다. Compose에서 Kotlin의 Sealed Classes를 최대한 활용할 수 있습니다. , 함수 유형 및 람다 식 .
컴포저블이 무엇인지 모르는 경우 기본 사항을 설명하는 이 기사를 읽어보십시오.
실드 클래스로 UI 이벤트를 모델링하는 방법
먼저 UI 이벤트의 의미와 실드 클래스로 모델링하는 방법을 배워야 합니다.
이전에 Java 및 Kotlin(이전 보기 시스템 사용)에 대해 이와 동일한 프로세스를 설명한 적이 있으므로 간략하게 설명하겠습니다.
프로세스
UI의 각 화면이나 하위 화면에 대해 다음과 같은 질문을 하십시오. 사용자가 상호 작용할 수 있는 모든 다른 방법은 무엇입니까?
Compose로 완전히 구축된 첫 번째 앱인 Graph Sudoku의 예를 들어 보겠습니다.
이 화면의 UI 상호 작용을 나타내는 데 사용하는 봉인된 클래스는 다음과 같습니다.
sealed class ActiveGameEvent {
data class OnInput(val input: Int) : ActiveGameEvent()
data class OnTileFocused(val x: Int,
val y: Int) : ActiveGameEvent()
object OnNewGameClicked : ActiveGameEvent()
object OnStart : ActiveGameEvent()
object OnStop : ActiveGameEvent()
}
간단히 설명하자면:
- OnInput은 입력 버튼(예:0, 1, 2, 3, 4)을 터치하는 사용자를 나타냅니다.
- OnTileFocused는 타일을 선택하는 사용자를 나타냅니다(예:주황색으로 강조 표시된 타일)
- OnNewGameClicked는 설명이 필요 없습니다.
- OnStart 및 OnStop은 내 컴포저블이 신경 쓰지 않는 수명 주기 이벤트이지만 컴포저블의 컨테이너 역할을 하는 활동에서 사용됩니다.
봉인된 클래스가 설정되면 이제 단일 이벤트 핸들러 함수를 사용하여 다양한 이벤트를 처리할 수 있습니다. 때로는 여러 이벤트 핸들러 함수를 사용하는 것이 더 합리적일 수 있으므로 이 접근 방식은 프로젝트의 특정 요구사항에 맞게 조정해야 합니다 .
소프트웨어 아키텍처를 연결하는 방법
이러한 이벤트를 처리하는 것은 전적으로 귀하에게 달려 있습니다. 어떤 사람들은 MVVM이 소프트웨어 아키텍처의 황금 표준이라고 생각하지만 점점 더 많은 사람들이 모든 상황에 가장 잘 맞는 단일 아키텍처가 없다는 사실을 깨닫고 있는 것 같습니다. .
Compose가 포함된 Android의 경우 현재 접근 방식은 일반적으로 각 기능(화면)에 다음과 같은 기능이 있는 타사의 미니멀리즘 접근 방식을 사용하는 것입니다.
- (프레젠테이션) 논리 클래스 이벤트 처리기
- View를 렌더링하는 데 필요한 데이터를 저장하는 ViewModel(이름에서 알 수 있듯이)
- 컨테이너 역할을 하는 활동(신 개체 아님)
- 뷰를 형성하기 위한 컴포저블
나는 당신이 관심사 분리를 적용하는 한 당신이 무엇을 사용하든 상관하지 않습니다. 이것이 내가 같은 수업에 함께 넣어야 하는 것과 하지 말아야 하는 것을 단순히 질문하여 이 아키텍처에 도달한 방법입니다.
ViewModel, Fragment 또는 Activity를 이벤트 처리기로 원하는지 여부에 관계없이 모두 동일한 방식으로 설정할 수 있습니다. 함수 유형!
선택한 클래스 내에서 봉인된 클래스를 인수로 받아들이는 이벤트 핸들러 함수를 설정합니다.
class ActiveGameLogic(
private val container: ActiveGameContainer?,
private val viewModel: ActiveGameViewModel,
private val gameRepo: IGameRepository,
private val statsRepo: IStatisticsRepository,
dispatcher: DispatcherProvider
) : BaseLogic<ActiveGameEvent>(dispatcher),
CoroutineScope {
//...
override fun onEvent(event: ActiveGameEvent) {
when (event) {
is ActiveGameEvent.OnInput -> onInput(
event.input,
viewModel.timerState
)
ActiveGameEvent.OnNewGameClicked -> onNewGameClicked()
ActiveGameEvent.OnStart -> onStart()
ActiveGameEvent.OnStop -> onStop()
is ActiveGameEvent.OnTileFocused -> onTileFocused(event.x, event.y)
}
}
//...
}
이 접근 방식은 매우 체계적이며 단일 진입점을 통해 이 타사 라이브러리 무료 클래스의 모든 단위를 쉽게 테스트할 수 있습니다.
그러나 아직 끝나지 않았습니다. 당연히 이 이벤트 핸들러 함수 onEvent
에 대한 참조를 얻는 방법이 필요합니다. , 컴포저블에. 함수 참조를 사용하여 이 작업을 수행할 수 있습니다. :
class ActiveGameActivity : AppCompatActivity(), ActiveGameContainer {
private lateinit var logic: ActiveGameLogic
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val viewModel = ActiveGameViewModel()
setContent {
ActiveGameScreen(
onEventHandler = logic::onEvent,
viewModel
)
}
logic = buildActiveGameLogic(this, viewModel, applicationContext)
}
//...
}
내가 Activity를 사용하는 이유를 궁금해 하시는 분들이 계실 것입니다. 자세한 답변은 생중계 Q&A 중에 물어볼 수 있습니다.
요컨대, Fragments는 Compose에서 아키텍처에 대한 접근 방식(저는 Jetpack Navigation을 사용하지 않음)으로 약간 무의미한 것으로 보이며 활동을 기능별 컨테이너로 사용하는 데 아무런 문제가 없습니다. 기본적으로 신의 활동을 작성하지 마십시오.
구체적으로 말하면 Kotlin에서 함수를 참조하는 방법은 클래스/인터페이스 이름을 제공하는 것입니다. (또는 최상위 함수인 경우 건너뛰기 ), 그 뒤에 콜론 2개 , 및 인수나 대괄호가 없는 함수 이름 :
onEventHandler = logic::onEvent
onClickListener를 Jetpack Compose onClick 수정자로 바꾸는 방법
해당 항목이 준비되면 컴포저블 내에서 이것이 어떻게 작동하는지 확인할 수 있습니다. 당연히 루트 컴포저블에는 이벤트 핸들러 함수가 매개변수로 필요합니다.
@Composable
fun ActiveGameScreen(
onEventHandler: (ActiveGameEvent) -> Unit,
viewModel: ActiveGameViewModel
) {
//...
}
함수 유형 구문을 올바르게 가져오는 것은 약간 까다로울 수 있지만 이것이 실제로는 함수에 대한 참조임을 이해하세요. 클래스에 대한 참조와 크게 다르지 않습니다.
신의 개체를 만들면 안 되는 것처럼 거대한 컴포저블도 만들면 안 됩니다.
- UI를 가장 작은 부분으로 나누기
- 구성 가능한 함수로 래핑
- 연결된 UI 상호작용이 있는 각 컴포저블에 대해 이벤트 핸들러 함수에 대한 참조를 제공해야 합니다
다음은 이벤트 핸들러가 참조로 제공되는 스도쿠 앱의 입력 버튼을 나타내는 컴포저블입니다.
@Composable
fun SudokuInputButton(
onEventHandler: (ActiveGameEvent) -> Unit,
number: Int
) {
Button(
onClick = { onEventHandler.invoke(ActiveGameEvent.OnInput(number)) },
modifier = Modifier
.requiredSize(56.dp)
.padding(2.dp)
) {
Text(
text = number.toString(),
style = inputButton.copy(color = MaterialTheme.colors.onPrimary),
modifier = Modifier.fillMaxSize()
)
}
}
이벤트를 로직 클래스에 실제로 전달하려면 invoke
을 사용해야 합니다. 함수 유형 정의에 따라 인수를 허용하는 함수(ActiveGameEvent
허용) 이 경우).
이제 이 아름답고 현대적인 프로그래밍 언어를 최대한 활용하여 Kotlin에서 UI 상호작용 이벤트(작성 여부)를 처리할 준비가 되었습니다.
이 기사가 마음에 들면 소셜 미디어에 공유하고 독립 프로그래머와 콘텐츠 제작자를 지원하기 위해 아래 리소스를 확인하는 것이 좋습니다.
소셜
여기 인스타그램과 여기 트위터에서 저를 찾을 수 있습니다.
내 튜토리얼 및 과정 중 일부는 다음과 같습니다.
https://youtube.com/wiseass https://www.freecodecamp.org/news/author/ryan-michael-kay/ https://skl.sh/35IdKsj (Android Studio와 Android 소개)