Computer >> 컴퓨터 >  >> 체계 >> Android

Jetpack Compose에서 UI 이벤트를 처리하는 방법

이 짧고 실용적인 기사에서는 Jetpack Compose에서 UI 이벤트를 처리하는 방법에 대해 설명합니다.

이전 시스템에서는 OnClickListeners 및 기타 인터페이스를 사용했습니다. Compose에서 Kotlin의 Sealed Classes를 최대한 활용할 수 있습니다. , 함수 유형람다 식 .

컴포저블이 무엇인지 모르는 경우 기본 사항을 설명하는 이 기사를 읽어보십시오.

이 기사는 이 동영상에서 3분 미만으로 요약되어 있습니다.

실드 클래스로 UI 이벤트를 모델링하는 방법

먼저 UI 이벤트의 의미와 실드 클래스로 모델링하는 방법을 배워야 합니다.

이전에 Java 및 Kotlin(이전 보기 시스템 사용)에 대해 이와 동일한 프로세스를 설명한 적이 있으므로 간략하게 설명하겠습니다.

프로세스

UI의 각 화면이나 하위 화면에 대해 다음과 같은 질문을 하십시오. 사용자가 상호 작용할 수 있는 모든 다른 방법은 무엇입니까?

Compose로 완전히 구축된 첫 번째 앱인 Graph Sudoku의 예를 들어 보겠습니다.

Jetpack Compose에서 UI 이벤트를 처리하는 방법
Sudoku Android 앱의 스크린샷

이 화면의 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(이름에서 알 수 있듯이)
  • 컨테이너 역할을 하는 활동(신 개체 아님)
  • 뷰를 형성하기 위한 컴포저블
Jetpack Compose에서 UI 이벤트를 처리하는 방법
모델 보기-무엇이든

나는 당신이 관심사 분리를 적용하는 한 당신이 무엇을 사용하든 상관하지 않습니다. 이것이 내가 같은 수업에 함께 넣어야 하는 것과 하지 말아야 하는 것을 단순히 질문하여 이 아키텍처에 도달한 방법입니다.

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
) {
//...
}

함수 유형 구문을 올바르게 가져오는 것은 약간 까다로울 수 있지만 이것이 실제로는 함수에 대한 참조임을 이해하세요. 클래스에 대한 참조와 크게 다르지 않습니다.

신의 개체를 만들면 안 되는 것처럼 거대한 컴포저블도 만들면 안 됩니다.

  1. UI를 가장 작은 부분으로 나누기
  2. 구성 가능한 함수로 래핑
  3. 연결된 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 소개)