Thực hành: Hành vi nhấp chuột

1. Trước khi bắt đầu

Trong lộ trình này, bạn đã học cách thêm một nút vào ứng dụng và sửa đổi ứng dụng đó để phản hồi một lượt nhấp chuột vào nút. Giờ là lúc thực hành những gì bạn được học bằng cách tạo một ứng dụng.

Bạn sẽ tạo một ứng dụng có tên là ứng dụng Lemonade. Trước tiên, hãy đọc các yêu cầu của ứng dụng Lemonade để hiểu rõ giao diện và cách hoạt động của nó. Nếu muốn thử thách bản thân, bạn có thể tự xây dựng ứng dụng từ đó. Nếu gặp khó khăn, bạn có thể đọc các phần tiếp theo để tìm gợi ý và hướng dẫn thêm về cách chia nhỏ cũng như tiếp cận vấn đề từng bước.

Giải quyết bài tập thực hành này với tiến độ bạn cảm thấy thoải mái. Hãy dành nhiều thời gian cần thiết nhất có thể để xây dựng từng chức năng của ứng dụng. Mã giải pháp cho ứng dụng Lemonade có ở phần cuối, nhưng bạn nên cố gắng tự xây dựng ứng dụng trước khi xem mã giải pháp. Hãy nhớ rằng mã giải pháp đã cho không phải là cách duy nhất để xây dựng ứng dụng Lemonade, vì vậy sẽ không có vấn đề gì nếu bạn xây dựng ứng dụng theo cách khác, miễn là đáp ứng các yêu cầu của ứng dụng.

Điều kiện tiên quyết

  • Có thể tạo một bố cục giao diện người dùng đơn giản trong Compose với thành phần kết hợp văn bản và hình ảnh
  • Có khả năng xây dựng một ứng dụng tương tác có thể phản hồi về lượt nhấp chuột vào nút
  • Có kiến thức cơ bản về thành phần kết hợp và kết hợp lại
  • Quen thuộc với các khái niệm cơ bản của ngôn ngữ lập trình Kotlin, bao gồm hàm, biến, điều kiện và hàm lambda

Bạn cần có

  • Máy tính có kết nối Internet và đã cài đặt Android Studio.

2. Tổng quan về ứng dụng

Bạn sẽ giúp chúng tôi hiện thực hóa mục tiêu số hóa hoạt động pha nước chanh! Mục tiêu là tạo ra một ứng dụng tương tác đơn giản cho phép bạn vắt chanh khi nhấn vào hình ảnh trên màn hình cho đến khi có một ly nước chanh. Hãy coi đây là một phép ẩn dụ hoặc có thể chỉ là một cách thú vị để giết thời gian!

dfcc3bc3eb43e4dd.png

Dưới đây là cách hoạt động của ứng dụng:

  1. Khi người dùng khởi chạy ứng dụng lần đầu tiên, họ sẽ thấy một cây chanh. Có một nhãn nhắc họ nhấn vào hình ảnh cây chanh để "chọn" một quả chanh từ cây chanh.
  2. Sau khi nhấn vào cây chanh, người dùng sẽ thấy một quả chanh. Họ được nhắc nhấn vào quả chanh để "vắt" lấy nước chanh. Họ cần nhấn vào trái chanh vài lần để vắt. Số lần nhấn cần thiết mỗi lần để vắt chanh sẽ khác nhau và là một số được tạo ngẫu nhiên từ 2 đến 4 (bao gồm cả 2 và 4).
  3. Sau khi nhấn vào quả chanh đúng số lần yêu cầu, họ sẽ có một ly nước chanh tươi ngon! Họ yêu cầu bạn nhấn vào ly để "uống" nước chanh.
  4. Sau khi nhấn vào ly nước chanh, họ sẽ thấy một ly trống. Họ được yêu cầu nhấn vào ly trống đó để bắt đầu lại.
  5. Sau khi nhấn vào ly trống, họ sẽ thấy cây chanh và có thể bắt đầu lại quá trình này. Vui lòng thêm nước chanh!

Dưới đây là ảnh chụp màn hình lớn hơn về giao diện của ứng dụng:

Tại mỗi bước làm nước chanh, trên màn hình sẽ có một hình ảnh và nhãn văn bản khác nhau cùng hành vi khác nhau cho cách ứng dụng phản hồi một lượt nhấp. Ví dụ: khi người dùng nhấn vào cây chanh, ứng dụng sẽ hiển thị một quả chanh.

Công việc của bạn là xây dựng bố cục giao diện người dùng của ứng dụng và triển khai logic để người dùng đi qua tất cả các bước để làm nước chanh.

3. Bắt đầu

Tạo một dự án

Trong Android Studio, hãy tạo một dự án mới bằng mẫu Hoạt động trống với các thông tin chi tiết sau:

  • Tên: Lemonade
  • Tên gói: com.example.lemonade
  • SDK tối thiểu: 24

Sau khi tạo xong ứng dụng và thư mục bản dựng của dự án, hãy chuyển sang phần tiếp theo.

Thêm hình ảnh

Bạn được cung cấp 4 tệp vectơ vẽ được để sử dụng trong ứng dụng Lemonade.

Các bước lấy tệp:

  1. Tải tệp zip của hình ảnh cho ứng dụng.
  2. Nhấp đúp vào tệp zip. Bước này sẽ giải nén các hình ảnh vào một thư mục.
  3. Thêm hình ảnh vào thư mục drawable của ứng dụng. Nếu bạn không nhớ cách thực hiện, hãy xem Lớp học lập trình ứng dụng về Tạo ứng dụng tương tác Dice Roller .

Thư mục dự án của bạn sẽ trông như ảnh chụp màn hình sau đây, trong đó các thành phần lemon_drink.xml, lemon_restart.xml, lemon_squeeze.xmllemon_tree.xml nay xuất hiện trong thư mục res > drawable:

ccc5a4aa8a7e9fbd.png

  1. Nhấp đúp vào một tệp vectơ vẽ được để xem trước hình ảnh.
  2. Chọn ngăn Thiết kế (chứ không chọn chế độ xem Code (Mã) hoặc Split (Phân tách)) để xem hình ảnh toàn chiều rộng.

3f3a1763ac414ec0.png

Sau khi tệp hình ảnh được đưa vào ứng dụng, bạn có thể tham chiếu đến chúng trong đoạn mã của mình. Ví dụ: nếu tệp có thể vẽ gọi là lemon_tree.xml, thì trong mã Kotlin, bạn có thể tham chiếu đến tệp có thể vẽ bằng mã tài nguyên của tệp theo định dạng R.drawable.lemon_tree.

Thêm tài nguyên chuỗi

Thêm các chuỗi sau vào dự án của bạn trong tệp res > values > strings.xml:

  • Tap the lemon tree to select a lemon
  • Keep tapping the lemon to squeeze it
  • Tap the lemonade to drink it
  • Tap the empty glass to start again

Bạn cũng cần các chuỗi sau trong dự án của mình. Chúng không hiển thị trên màn hình trong giao diện người dùng, nhưng được dùng cho nội dung hình ảnh của ứng dụng, để mô tả những hình ảnh đó là gì. Thêm các chuỗi bổ sung này vào tệp strings.xml của ứng dụng:

  • Lemon tree
  • Lemon
  • Glass of lemonade
  • Empty glass

Nếu bạn không nhớ cách khai báo tài nguyên chuỗi trong ứng dụng, hãy xem phần Lớp học lập trình ứng dụng về Tạo ứng dụng tương tác Dice Roller hoặc tham khảo Chuỗi. Đặt cho mỗi tài nguyên chuỗi một tên nhận dạng thích hợp để mô tả giá trị của nó. Ví dụ: đối với chuỗi "Lemon", bạn có thể khai báo chuỗi này trong tệp strings.xml với tên nhận dạng là lemon_content_description, sau đó tham chiếu đến mã này trong mã của bạn bằng cách sử dụng mã tài nguyên: R.string.lemon_content_description.

Các bước làm nước chanh

Giờ bạn đã có tài nguyên chuỗi và thành phần hình ảnh cần thiết để triển khai ứng dụng. Dưới đây là tóm tắt từng bước của ứng dụng và nội dung hiển thị trên màn hình:

Bước 1:

  • Nội dung văn bản: Tap the lemon tree to select a lemon
  • Hình ảnh: Cây chanh (lemon_tree.xml)

b2b0ae4400c0d06d.png

Bước 2:

  • Nội dung văn bản: Keep tapping the lemon to squeeze it
  • Hình ảnh: Quả chanh (lemon_squeeze.xml)

7c6281156d027a8.png

Bước 3:

  • Nội dung văn bản: Tap the lemonade to drink it
  • Hình ảnh: Ly nước chanh đầy (lemon_drink.xml)

38340dfe3df0f721.png

Bước 4:

  • Nội dung văn bản: Tap the empty glass to start again
  • Hình ảnh: Ly trống (lemon_restart.xml)

e9442e201777352b.png

Trau chuốt thêm cho phần hình ảnh

Để phiên bản ứng dụng của bạn trông đẹp như những ảnh chụp màn hình hoàn thiện này, bạn có thể thực hiện một vài điều chỉnh trực quan hơn trong ứng dụng:

  • Tăng cỡ chữ của văn bản sao cho lớn hơn cỡ chữ mặc định (chẳng hạn như 18sp).
  • Tăng khoảng trống giữa nhãn văn bản và hình ảnh bên dưới nhãn, để chúng không quá gần nhau (chẳng hạn như 16dp).
  • Tạo màu nhấn cho nút và bo tròn nhẹ các góc để người dùng biết rằng họ có thể nhấn vào hình ảnh.

Nếu bạn muốn thử thách bản thân, hãy xây dựng phần còn lại của ứng dụng dựa trên mô tả về cách hoạt động của nó. Nếu bạn muốn được hướng dẫn thêm, hãy chuyển sang phần tiếp theo.

4. Lên kế hoạch cách xây dựng ứng dụng

Khi xây dựng ứng dụng, bạn nên tạo trước một phiên bản ứng dụng hoạt động sơ khởi nhất. Sau đó, hãy thêm dần chức năng cho đến khi bạn hoàn tất tất cả chức năng mong muốn. Xác định một chức năng đơn giản bạn có thể tạo trước từ đầu đến cuối.

Trong ứng dụng Lemonade, hãy lưu ý phần quan trọng của ứng dụng là việc chuyển đổi từ bước này sang bước khác với hình ảnh và nhãn văn bản khác nhau được hiển thị cho mỗi lần. Ban đầu, có thể bỏ qua hành vi đặc biệt của trạng thái vắt vì bạn có thể thêm chức năng này sau khi đã xây dựng nền tảng của ứng dụng.

Dưới đây là đề xuất tổng quan cấp cao về các bước bạn có thể thực hiện để tạo ứng dụng:

  1. Xây dựng bố cục giao diện người dùng ở bước đầu tiên trong việc làm nước chanh, là nhắc người dùng chọn quả chanh từ cây chanh. Bạn hiện có thể bỏ qua đường viền xung quanh hình ảnh vì đó là chi tiết hình ảnh có thể thêm vào sau này.

b2b0ae4400c0d06d.png

  1. Triển khai hành vi trong ứng dụng để khi người dùng nhấn vào cây chanh, ứng dụng sẽ cho thấy hình ảnh quả chanh và nhãn văn bản tương ứng. Việc này mô tả hai bước đầu tiên để làm nước chanh.

adbf0d217e1ac77d.png

  1. Bổ sung mã để ứng dụng hiển thị các bước còn lại để làm ra nước chanh, mỗi khi hình ảnh được nhấn vào. Tại thời điểm này, chỉ một lần nhấn vào quả chanh có thể chuyển sang hình ảnh một ly nước chanh.

Có 4 ô được xếp theo hàng ngang, mỗi ô có một đường viền màu xanh lục. Mỗi ô chứa một số từ 1 đến 4. Có một mũi tên từ ô 1 đến ô 2, từ ô 2 đến ô 3, từ ô 3 đến ô 4 và từ ô 4 quay lại ô 1. Dưới ô 1 là nhãn văn bản với nội dung: Nhấn vào cây chanh để chọn một quả chanh; và hình ảnh cây chanh. Dưới ô 2 là nhãn văn bản với nội dung: Tiếp tục nhấn vào quả chanh để vắt; và hình ảnh một quả chanh. Dưới ô 3 là nhãn văn bản với nội dung: Nhấn vào nước chanh để uống; và hình ảnh một ly nước chanh. Dưới ô 4 là nhãn văn bản với nội dung: Nhấn vào ly trống để bắt đầu lại; và hình ảnh một chiếc ly trống.

  1. Thêm hành vi tuỳ chỉnh cho bước vắt chanh để người dùng cần phải "vắt" hoặc nhấn vào quả chanh theo số lần được tạo ngẫu nhiên từ 2 đến 4.

Có 4 ô được xếp theo hàng ngang, mỗi ô có một đường viền màu xanh lục. Mỗi ô chứa một số từ 1 đến 4. Có một mũi tên từ ô 1 đến ô 2, từ ô 2 đến ô 3, từ ô 3 đến ô 4 và từ ô 4 quay lại ô 1. Có thêm một mũi tên từ ô 2 trở lại chính nó với nhãn: Số lần ngẫu nhiên. Dưới ô 1 là hình cây chanh và nhãn văn bản tương ứng. Dưới ô 2 là hình quả chanh và nhãn văn bản tương ứng. Dưới ô 3 là hình một ly nước chanh và nhãn văn bản tương ứng. Dưới ô 4 là hình một ly trống và nhãn văn bản tương ứng.

  1. Hoàn thiện ứng dụng với bất kỳ chi tiết tinh chỉnh hình ảnh cần thiết khác. Ví dụ: thay đổi cỡ chữ và thêm đường viền xung quanh hình ảnh để làm cho ứng dụng trông đẹp mắt hơn. Xác minh việc ứng dụng tuân thủ các phương pháp viết mã tốt, chẳng hạn như tuân thủ Nguyên tắc về kiểu lập trình Kotlin và thêm nhận xét vào mã.

Nếu bạn có thể sử dụng các bước cao cấp này làm kim chỉ nam trong quá trình triển khai ứng dụng Lemonade, hãy tiếp tục và tự xây dựng ứng dụng. Nếu bạn nhận thấy mình cần thêm hướng dẫn về từng bước trong số 5 bước này, hãy chuyển sang phần tiếp theo.

5. Triển khai ứng dụng

Tạo bố cục giao diện người dùng

Trước tiên, hãy thay đổi ứng dụng để nó hiển thị hình ảnh cây chanh và nhãn văn bản tương ứng của ứng dụng, biểu thị Tap the lemon tree to select a lemon, ở giữa màn hình. Bạn cũng nên tạo khoảng cách là 16dp giữa văn bản và hình ảnh bên dưới văn bản.

b2b0ae4400c0d06d.png

Nếu cách này hữu ích, bạn có thể sử dụng đoạn mã khởi đầu sau đây trong tệp MainActivity.kt:

package com.example.lemonade

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.lemonade.ui.theme.LemonadeTheme

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           LemonadeTheme {
               LemonApp()
           }
       }
   }
}

@Composable
fun LemonApp() {
   // A surface container using the 'background' color from the theme
   Surface(
       modifier = Modifier.fillMaxSize(),
       color = MaterialTheme.colorScheme.background
   ) {
       Text(text = "Hello there!")
   }
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
   LemonadeTheme {
       LemonApp()
   }
}

Mã này tương tự như mã do Android Studio tạo tự động. Tuy nhiên, thay vì dùng thành phần kết hợp Greeting(), có một thành phần kết hợp xác định là LemonApp() và nó không có tham số. Thành phần kết hợp DefaultPreview() cũng được cập nhật để sử dụng thành phần kết hợp LemonApp(), nhờ đó bạn có thể dễ dàng xem trước mã của mình.

Sau khi bạn nhập mã này vào Android Studio, hãy sửa đổi thành phần kết hợp LemonApp(), và nó phải chứa nội dung của ứng dụng. Dưới đây là một số câu hỏi để định hình quá trình tư duy của bạn:

  • Bạn sẽ dùng những thành phần kết hợp nào?
  • Thành phần bố cục Compose chuẩn nào có thể giúp bạn sắp xếp các thành phần kết hợp vào vị trí mong muốn không?

Hãy triển khai bước này để cây chanh và nhãn văn bản xuất hiện trong ứng dụng khi ứng dụng khởi chạy. Xem trước thành phần kết hợp trong Android Studio để xem giao diện người dùng sẽ hiển thị như thế nào khi bạn sửa đổi mã. Chạy ứng dụng để đảm bảo nó trông giống như ảnh chụp màn hình bạn đã thấy trước đó trong phần này.

Hãy quay lại hướng dẫn này sau khi hoàn tất nếu bạn muốn được hướng dẫn thêm về cách thêm hành vi khi hình ảnh được nhấn vào.

Thêm hành vi nhấp chuột

Tiếp theo, bạn sẽ thêm mã để khi người dùng nhấn vào hình cây chanh, hình ảnh của quả chanh sẽ xuất hiện cùng với nhãn văn bản Keep tapping the lemon to squeeze it. Nói cách khác, khi bạn nhấn vào cây chanh, văn bản và hình ảnh sẽ thay đổi.

adbf0d217e1ac77d.png

Trong phần trước của lộ trình học tập này, bạn đã học cách tạo một nút có thể nhấp được. Trong trường hợp ứng dụng Lemonade, không có thành phần kết hợp Button nào. Tuy nhiên, bạn có thể tạo bất kỳ thành phần kết hợp nào, không chỉ các nút, có thể nhấp khi bạn chỉ định đối tượng sửa đổi clickable trên đó. Ví dụ: hãy xem trang tài liệu khả năng nhấp.

Điều gì sẽ xảy ra khi người dùng nhấp vào hình ảnh đó? Mã để triển khai hành vi này không quan trọng, vì vậy, hãy trở lại dùng một ứng dụng quen thuộc khác.

Hãy xem lại ứng dụng Dice Roller

Xem lại mã từ ứng dụng Dice Roller để quan sát cách ứng dụng hiển thị các hình ảnh xúc xắc dựa trên giá trị của xúc xắc:

MainActivity.kt trong ứng dụng Dice Roller

...

@Composable
fun DiceWithButtonAndImage(modifier: Modifier = Modifier) {
   var result by remember { mutableStateOf(1) }
   val imageResource = when(result) {
       1 -> R.drawable.dice_1
       2 -> R.drawable.dice_2
       3 -> R.drawable.dice_3
       4 -> R.drawable.dice_4
       5 -> R.drawable.dice_5
       else -> R.drawable.dice_6
   }
   Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) {
       Image(painter = painterResource(id = imageResource), contentDescription = result.toString())
       Button(onClick = { result = (1..6).random() }) {
          Text(stringResource(id = R.string.roll))
       }
   }
}

...

Trả lời những câu hỏi sau về mã ứng dụng Dice Roller:

  • Giá trị nào của biến xác định hình ảnh xúc xắc phù hợp để hiển thị?
  • Hành động nào từ người dùng sẽ kích hoạt biến đó thay đổi?

Hàm kết hợp DiceWithButtonAndImage() lưu trữ cuộn xúc xắc gần đây nhất, trong biến result, được xác định bằng thành phần kết hợp remember và hàm mutableStateOf() trong dòng mã này:

var result by remember { mutableStateOf(1) }

Khi biến result được cập nhật thành giá trị mới, Compose kích hoạt tính năng kết hợp lại của thành phần kết hợp DiceWithButtonAndImage(), có nghĩa là thành phần kết hợp sẽ thực thi lại. Giá trị result được ghi nhớ trên các tính năng kết hợp lại, do đó, khi thành phần kết hợp DiceWithButtonAndImage() chạy lại, giá trị result gần đây nhất sẽ được sử dụng. Sử dụng một câu lệnh when về giá trị của biến result, thành phần kết hợp sẽ xác định mã tài nguyên có thể vẽ mới để hiển thị và thành phần kết hợp Image hiển thị nó.

Áp dụng những gì bạn đã học vào ứng dụng Lemonade

Bây giờ, hãy trả lời các câu hỏi tương tự về ứng dụng Lemonade:

  • Có biến nào bạn có thể sử dụng để xác định văn bản và hình ảnh sẽ hiển thị trên màn hình không? Xác định biến đó trong mã của bạn.
  • Bạn có thể sử dụng các điều kiện trong Kotlin để ứng dụng thực hiện hành vi khác nhau dựa trên giá trị của biến đó không? Nếu có, hãy viết câu lệnh có điều kiện đó trong mã của bạn.
  • Hành động nào từ người dùng sẽ kích hoạt biến đó thay đổi? Tìm vị trí thích hợp trong mã nơi việc đó xảy ra. Thêm mã vào đó để cập nhật biến.

Phần này có thể hơi khó triển khai và yêu cầu thay đổi ở nhiều vị trí của mã để có thể hoạt động chính xác. Đừng nản lòng nếu ứng dụng không hoạt động ngay lập tức như kỳ vọng của bạn. Hãy nhớ có nhiều cách đúng để triển khai hành vi này.

Khi bạn thực hiện xong, hãy chạy ứng dụng và xác minh nó có hoạt động. Khi bạn khởi chạy ứng dụng, nó sẽ hiển thị hình ảnh cây chanh và nhãn văn bản tương ứng của nó. Việc nhấn vào hình ảnh cây chanh sẽ thay đổi nhãn văn bản và hiển thị hình ảnh quả chanh. Tạm thời, việc nhấn vào hình ảnh quả chanh sẽ không có gì xảy ra cả.

Thêm các bước còn lại

Giờ đây, ứng dụng có thể hiển thị hai bước đầu để làm nước chanh! Tại bước này, thành phần kết hợp LemonApp() có thể trông giống như đoạn mã sau. Mã của bạn trông có hơi khác cũng không vấn đề gì, miễn là hành vi trong ứng dụng giống nhau.

MainActivity.kt

...
@Composable
fun LemonApp() {
   // Current step the app is displaying (remember allows the state to be retained
   // across recompositions).
   var currentStep by remember { mutableStateOf(1) }

   // A surface container using the 'background' color from the theme
   Surface(
       modifier = Modifier.fillMaxSize(),
       color = MaterialTheme.colorScheme.background
   ) {
       when (currentStep) {
           1 -> {
               Column (
                   horizontalAlignment = Alignment.CenterHorizontally,
                   verticalArrangement = Arrangement.Center,
                   modifier = Modifier.fillMaxSize()
               ){
                   Text(text = stringResource(R.string.lemon_select))
                   Spacer(modifier = Modifier.height(32.dp))
                   Image(
                       painter = painterResource(R.drawable.lemon_tree),
                       contentDescription = stringResource(R.string.lemon_tree_content_description),
                       modifier = Modifier
                           .wrapContentSize()
                           .clickable {
                               currentStep = 2
                           }
                   )
               }
           }
           2 -> {
               Column (
                   horizontalAlignment = Alignment.CenterHorizontally,
                   verticalArrangement = Arrangement.Center,
                   modifier = Modifier.fillMaxSize()
               ){
                   Text(text = stringResource(R.string.lemon_squeeze))
                   Spacer(modifier = Modifier.height(32
                       .dp))
                   Image(
                       painter = painterResource(R.drawable.lemon_squeeze),
                       contentDescription = stringResource(R.string.lemon_content_description),
                       modifier = Modifier.wrapContentSize()
                   )
               }
           }
       }
   }
}
...

Tiếp theo, bạn sẽ thêm các bước còn lại để làm nước chanh. Một cú nhấp vào hình ảnh sẽ chuyển người dùng đến bước tiếp theo là tạo ra nước chanh, trong đó cả văn bản và hình ảnh đều được cập nhật. Bạn cần thay đổi mã để tăng tính xử lý mã cho mọi bước trong ứng dụng chứ không chỉ hai bước đầu tiên.

Có 4 ô được xếp theo hàng ngang, mỗi ô có một đường viền màu xanh lục. Mỗi ô chứa một số từ 1 đến 4. Có một mũi tên từ ô 1 đến ô 2, từ ô 2 đến ô 3, từ ô 3 đến ô 4 và từ ô 4 quay lại ô 1. Dưới ô 1 là nhãn văn bản với nội dung: Nhấn vào cây chanh để chọn một quả chanh; và hình ảnh một cây chanh . Dưới ô 2 là nhãn văn bản với nội dung: Tiếp tục nhấn vào quả chanh để vắt; và hình một quả chanh. Dưới ô 3 là nhãn văn bản với nội dung: Nhấn vào nước chanh để uống; và hình ảnh một ly nước chanh. Dưới ô 4 là nhãn văn bản với nội dung: Nhấn vào ly trống để bắt đầu lại; và hình ảnh một chiếc ly trống.

Để có hành vi khác nhau mỗi khi người dùng nhấp vào hình ảnh, bạn cần tuỳ chỉnh hành vi có thể nhấp. Cụ thể hơn, hàm lambda được thực thi khi hình ảnh được nhấp vào cần biết chúng ta đang chuyển sang bước nào.

Bạn có thể bắt đầu nhận thấy có nhiều lần lặp lại mã trong ứng dụng cho mỗi bước làm nước chanh. Đối với câu lệnh when trong đoạn mã trước, mã cho trường hợp 1 rất giống với trường hợp 2 nhưng có sự khác biệt nhỏ. Hãy tạo một hàm kết hợp mới LemonTextAndImage() nếu việc đó hữu ích, chẳng hạn để hiển thị văn bản phía trên một hình ảnh trong giao diện người dùng. Bằng cách tạo một hàm mới, có khả năng kết hợp và một vài tham số đầu vào, bạn sẽ có một hàm có thể tái sử dụng và hữu ích trong nhiều trường hợp miễn là bạn thay đổi các giá trị đầu vào đã truyền. Bạn phải tìm ra các tham số đầu vào. Sau khi bạn tạo hàm kết hợp này, hãy cập nhật mã hiện có để gọi hàm mới này ở những vị trí liên quan.

Một lợi thế khác khi có một thành phần kết hợp riêng như LemonTextAndImage(), mã của bạn trở nên gọn gàng và linh hoạt hơn. Khi gọi LemonTextAndImage(), bạn phải chắc chắn cả văn bản và hình ảnh sẽ được cập nhật theo giá trị mới. Nếu không, rất dễ dàng vô tình bỏ lỡ một trường hợp nhãn văn bản được cập nhật hiển thị không tương ứng với hình ảnh.

Dưới đây là một gợi ý bổ sung: Bạn thậm chí có thể truyền hàm lambda vào một hàm kết hợp. Hãy nhớ dùng ký hiệu loại hàm để chỉ định loại hàm cần truyền vào. Trong ví dụ sau đây, thành phần kết hợp WelcomeScreen() được xác định và chấp nhận 2 tham số đầu vào: chuỗi name và hàm onStartClicked() của loại () -> Unit. Điều đó có nghĩa là hàm không nhận giá trị nhập (dấu ngoặc đơn trống trước mũi tên) và không có giá trị trả về ( Unit theo sau mũi tên). Bạn có thể dùng bất kỳ hàm nào khớp với loại hàm () -> Unit đó để đặt trình xử lý onClick của Button này. Khi người dùng nhấp vào nút này, hàm onStartClicked() sẽ được gọi.

@Composable
fun WelcomeScreen(name: String, onStartClicked: () -> Unit) {
    Column {
        Text(text = "Welcome $name!")
        Button(
            onClick = onStartClicked
        ) {
            Text("Start")
        }
    }
}

Việc truyền hàm lambda vào một thành phần kết hợp là một mẫu hữu ích vì sau đó có thể sử dụng lại thành phần kết hợp WelcomeScreen() trong các tình huống khác. Tên của người dùng và hành vi onClick của nút có thể khác nhau mỗi lần vì chúng được truyền vào dưới dạng đối số.

Với kiến thức bổ sung này, hãy quay lại mã của bạn để thêm các bước pha nước chanh còn lại vào ứng dụng.

Quay lại các hướng dẫn này nếu bạn muốn được hướng dẫn thêm về cách thêm logic tuỳ chỉnh việc vắt chanh với số lần ngẫu nhiên.

Thêm logic vắt

Tuyệt vời! Giờ bạn đã có kiến thức cơ bản về ứng dụng. Hãy nhấn vào hình ảnh để chuyển sang bước tiếp theo. Đã đến lúc thêm hành vi cần thiết của việc vắt trái chanh nhiều lần để làm nước chanh. Số lần người dùng cần vắt hoặc nhấn, trái chanh sẽ là một số ngẫu nhiên từ 2 đến 4 (bao gồm cả 2 và 4). Con số ngẫu nhiên này sẽ khác nhau mỗi khi người dùng chọn một quả chanh mới từ cây chanh.

Có 4 ô được xếp theo hàng ngang, mỗi ô có một đường viền màu xanh lục. Mỗi ô chứa một số từ 1 đến 4. Có một mũi tên từ ô 1 đến ô 2, từ ô 2 đến ô 3, từ ô 3 đến ô 4 và từ ô 4 quay lại ô 1. Còn có thêm một mũi tên từ hộp 2 trở lại chính nó với nhãn có nội dung: Số lần ngẫu nhiên; Dưới ô 1 là hình cây chanh và nhãn văn bản tương ứng. Dưới ô 2 là hình quả chanh và nhãn văn bản tương ứng. Dưới ô 3 là hình một ly nước chanh và nhãn văn bản tương ứng. Dưới ô 4 là hình một ly trống và nhãn văn bản tương ứng.

Dưới đây là một số câu hỏi để định hình quy trình tư duy của bạn:

  • Làm cách nào để tạo số ngẫu nhiên trong Kotlin?
  • Bạn nên tạo số ngẫu nhiên ở thời điểm nào trong mã của mình?
  • Làm cách nào để bạn đảm bảo người dùng nhấn vào trái chanh số lần đáp ứng theo yêu cầu trước khi chuyển sang bước tiếp theo?
  • Bạn có cần bất kỳ biến nào được lưu trữ cùng với thành phần kết hợp remember để dữ liệu không bị đặt lại mỗi khi màn hình được vẽ lại không?

Khi bạn triển khai xong thay đổi này, hãy chạy ứng dụng. Xác minh rằng phải thực hiện nhiều lần nhấn vào hình quả chanh để chuyển sang bước tiếp theo, và số lần nhấn cần thiết là một số ngẫu nhiên trong khoảng từ 2 đến 4. Nếu chỉ một lần nhấn vào hình ảnh quả chanh đã hiện ra ly nước chanh, hãy quay lại mã để tìm hiểu xem có gì sai sót và thử lại.

Hãy quay lại hướng dẫn này nếu bạn muốn được hướng dẫn thêm về cách hoàn thiện ứng dụng.

Hoàn thiện ứng dụng

Bạn sắp hoàn tất! Thêm một vài chi tiết cuối cùng để tinh chỉnh lại ứng dụng.

Lưu ý đây là những ảnh chụp màn hình về giao diện hoàn thiện của ứng dụng:

  • Căn giữa theo chiều dọc và chiều ngang của văn bản và hình ảnh bên trong màn hình.
  • Đặt cỡ chữ của văn bản thành 18sp.
  • Thêm 16dp khoảng cách giữa văn bản và hình ảnh.
  • Thêm đường viền mỏng khoảng 2dp bao quanh hình ảnh có các góc bo tròn khoảng 4dp. Đường viền có giá trị màu RGB105 cho màu đỏ, 205 cho màu xanh lục và 216 cho màu xanh lam. Ví dụ về cách thêm đường viền, bạn có thể tìm hướng dẫn trên Google. Hoặc bạn có thể tham khảo tài liệu về Đường viền.

Khi bạn đã hoàn tất những thay đổi này, hãy chạy ứng dụng và sau đó so sánh nó với ảnh chụp màn hình của ứng dụng hoàn thiện để đảm bảo chúng giống nhau.

Như một phần trong phương pháp lập trình tốt, hãy quay lại và thêm nhận xét vào mã để bất kỳ ai đọc mã đều có thể hiểu được quy trình tư duy của bạn dễ dàng hơn. Xóa bất kỳ câu lệnh nhập nào ở đầu tệp không được sử dụng trong mã. Đảm bảo mã của bạn tuân thủ hướng dẫn về kiểu Kotlin. Tất cả những nỗ lực này sẽ giúp người khác dễ dàng đọc mã của bạn và dễ bảo trì hơn!

Rất tốt! Bạn đã hoàn thành xuất sắc việc triển khai ứng dụng Lemonade! Đó là một ứng dụng đầy thử thách với nhiều phần cần tìm giải pháp. Giờ hãy tự thưởng cho mình một ly nước chanh tươi ngon. Chúc mừng!

6. Lấy mã giải pháp

Tải mã giải pháp:

Ngoài ra, bạn có thể sao chép kho lưu trữ GitHub cho mã:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-lemonade.git

Hãy nhớ mã của bạn không cần phải chính xác với mã giải pháp vì có nhiều cách để triển khai ứng dụng.

Bạn cũng có thể duyệt xem mã trong Kho lưu trữ GitHub của ứng dụng Lemonade.