Computer >> Máy Tính >  >> Hệ thống >> Android

Cách xử lý các sự kiện giao diện người dùng trong Jetpack Compose

Trong bài viết ngắn và thiết thực này, chúng ta sẽ nói về cách xử lý các sự kiện UI trong Jetpack Compose.

Trong hệ thống cũ, chúng tôi đã sử dụng OnClickListaries và các giao diện khác. Trong Soạn, chúng ta có thể tận dụng tối đa Lớp học kín của Kotlin , Loại chức năng Biểu thức Lambda .

Nếu bạn không biết tổng hợp là gì, hãy xem xét đọc bài viết này giải thích các nguyên tắc cơ bản.

Bài viết này được tóm tắt trong video này dưới 3 phút.

Cách tạo mô hình sự kiện giao diện người dùng với một lớp kín

Trước tiên, chúng ta phải tìm hiểu ý nghĩa của Sự kiện giao diện người dùng và cách lập mô hình chúng với Lớp kín.

Tôi đã mô tả quá trình tương tự này cho Java và Kotlin (với hệ thống chế độ xem cũ) trước đây, vì vậy tôi sẽ giữ lại phần này ngắn gọn.

Quy trình

Đối với mỗi màn hình hoặc màn hình phụ của giao diện người dùng, hãy tự hỏi mình câu hỏi này:Tất cả các cách khác nhau mà người dùng có thể tương tác với nó là gì?

Hãy lấy một ví dụ từ ứng dụng đầu tiên của tôi được tích hợp hoàn toàn trong soạn thư, Graph Sudoku:

Cách xử lý các sự kiện giao diện người dùng trong Jetpack Compose
Ảnh chụp màn hình Ứng dụng Sudoku Android

Lớp được niêm phong mà tôi sử dụng để đại diện cho các tương tác giao diện người dùng của màn hình này trông giống như sau:

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()
}

Để giải thích ngắn gọn:

  • OnInput biểu thị người dùng chạm vào nút đầu vào (như 0, 1, 2, 3, 4)
  • OnTileFocused thể hiện việc người dùng chọn một ô (như ô được đánh dấu màu hổ phách)
  • OnNewGameClicked tự giải thích
  • OnStart và OnStop là các sự kiện trong vòng đời mà các bản tổng hợp của tôi không quan tâm, nhưng chúng được sử dụng trong Hoạt động đóng vai trò như một Vùng chứa cho các bản tổng hợp

Khi bạn đã thiết lập lớp kín của mình, giờ đây bạn có thể xử lý nhiều sự kiện khác nhau bằng cách sử dụng một chức năng xử lý sự kiện duy nhất. Đôi khi có thể có ý nghĩa hơn khi có nhiều chức năng xử lý sự kiện, vì vậy hãy nhớ rằng cách tiếp cận này phải được điều chỉnh cho phù hợp với các yêu cầu cụ thể của dự án của bạn .

Cách kết nối kiến ​​trúc phần mềm của bạn

Những gì bạn có để xử lý những sự kiện này là hoàn toàn tùy thuộc vào bạn. Một số người nghĩ rằng MVVM là tiêu chuẩn vàng của kiến ​​trúc phần mềm, nhưng có vẻ như ngày càng nhiều người nhận ra rằng không có kiến ​​trúc duy nhất nào hoạt động tốt nhất cho mọi tình huống .

Đối với Android có tính năng Soạn thư, phương pháp hiện tại của tôi là sử dụng phương pháp tối giản của bên thứ 3 thường có những điều này trong mỗi tính năng (màn hình):

  • Lớp logic A (Trình bày) như một trình xử lý sự kiện
  • Một ViewModel để lưu trữ dữ liệu cần thiết để hiển thị Chế độ xem (như tên của nó)
  • Một Hoạt động hoạt động như một Vật chứa (không phải một vật thể thần thánh)
  • Các thành phần tổng hợp để tạo thành Chế độ xem
Cách xử lý các sự kiện giao diện người dùng trong Jetpack Compose
Model-View-Anything

Tôi không quan tâm bạn sử dụng gì miễn là bạn đang áp dụng tách biệt các mối quan tâm. Đây là cách tôi đến với kiến ​​trúc này, chỉ bằng cách hỏi những gì nên và không nên ghép chung vào cùng một lớp.

Cho dù bạn muốn ViewModel, Fragment hay Activity làm trình xử lý sự kiện của mình, tất cả chúng đều có thể được thiết lập theo cùng một cách: Loại hàm!

Trong lớp bạn chọn, hãy thiết lập một hàm xử lý sự kiện chấp nhận lớp được niêm phong của bạn làm đối số của nó:

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

Cách tiếp cận này rất có tổ chức và giúp bạn dễ dàng kiểm tra mọi Bài học trong lớp học miễn phí của thư viện bên thứ 3 này thông qua một điểm nhập duy nhất.

Tuy nhiên, chúng tôi vẫn chưa xong. Đương nhiên, chúng ta cần một cách để tham chiếu đến hàm xử lý sự kiện này, onEvent , cho Composables của chúng tôi. Chúng tôi có thể thực hiện việc này bằng cách sử dụng tham chiếu hàm :

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)
    }

  	//...
}

Tôi chắc chắn rằng một số bạn đang thắc mắc tại sao tôi lại sử dụng Activity. Đôi khi, bạn có thể hỏi tôi trong một buổi hỏi đáp trực tiếp để có câu trả lời chi tiết.

Nói tóm lại, Fragment có vẻ hơi vô nghĩa với Soạn thảo với cách tiếp cận kiến ​​trúc của tôi (tôi không sử dụng Jetpack Navigation) và không có gì sai khi sử dụng Hoạt động làm vùng chứa tính năng cụ thể. Về cơ bản, chỉ cần tránh viết các hoạt động thần thánh.

Cụ thể, cách bạn tạo tham chiếu đến một hàm trong Kotlin là cung cấp tên lớp / giao diện (hoặc bỏ qua nếu đó là chức năng Cấp cao nhất ), theo sau là hai dấu hai chấm tên của hàm không có bất kỳ đối số hoặc dấu ngoặc vuông nào :

onEventHandler = logic::onEvent

Cách thay thế onClickListener bằng Jetpack Soạn onClick Modifier

Với những thứ đó đã sẵn sàng, chúng ta có thể xem nó hoạt động như thế nào trong bản tổng hợp. Đương nhiên, có thể tổng hợp gốc của bạn sẽ cần hàm xử lý sự kiện như một tham số:

@Composable
fun ActiveGameScreen(
    onEventHandler: (ActiveGameEvent) -> Unit,
    viewModel: ActiveGameViewModel
) {
//...
}

Có thể hơi phức tạp để có được cú pháp loại hàm một cách chính xác, nhưng hãy hiểu rằng điều này thực sự là một tham chiếu đến một hàm, không quá khác biệt so với tham chiếu đến một lớp.

Cũng như bạn không nên xây dựng các vật thể thần, bạn không nên xây dựng các vật thể tổng hợp khổng lồ:

  1. Chia nhỏ giao diện người dùng của bạn thành các phần hợp lý nhỏ nhất
  2. Kết hợp chúng trong một chức năng có thể kết hợp
  3. Đối với mỗi tệp có thể kết hợp có tương tác với giao diện người dùng, tệp đó phải được cung cấp tham chiếu đến chức năng xử lý sự kiện của bạn

Đây là một tập hợp đại diện cho các nút đầu vào của ứng dụng Sudoku, được cung cấp cho trình xử lý sự kiện bằng cách tham khảo:

@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()
        )
    }
}

Để thực sự chuyển sự kiện vào lớp logic, chúng ta phải sử dụng invoke hàm, sẽ chấp nhận các đối số theo định nghĩa kiểu hàm (chấp nhận ActiveGameEvent trong trường hợp này).

Tại thời điểm này, bạn đã sẵn sàng xử lý các sự kiện tương tác giao diện người dùng trong Kotlin (soạn hoặc không) bằng cách tận dụng tối đa ngôn ngữ lập trình đẹp và hiện đại này.

Nếu bạn thích bài viết này, hãy chia sẻ nó trên phương tiện truyền thông xã hội và xem xét kiểm tra các tài nguyên bên dưới để hỗ trợ một nhà lập trình và người sáng tạo nội dung độc lập.

Xã hội

Bạn có thể tìm thấy tôi trên Instagram tại đây và trên Twitter tại đây.

Đây là một số hướng dẫn và khóa học của tôi

https://youtube.com/wiseass https://www.freecodecamp.org/news/author/ryan-michael-kay/ https://skl.sh/35IdKsj (giới thiệu về Android với Android Studio)