Tính toán tiền boa tuỳ chỉnh

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

Trong lớp học lập trình này, bạn sẽ sử dụng mã nguồn giải pháp từ lớp học lập trình Giới thiệu về trạng thái trong Compose để tạo một công cụ tính tiền boa mang tính tương tác. Công cụ này có thể tự động tính toán và làm tròn số tiền boa khi bạn nhập số tiền trên hoá đơn và tỷ lệ phần trăm boa. Dưới đây là ảnh chụp màn hình khi ứng dụng đã hoàn thiện.

d8e768525099378a.png

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

  • Lớp học lập trình Giới thiệu về trạng thái trong Compose.
  • Khả năng thêm thành phần kết hợp TextTextField vào một ứng dụng.
  • Kiến thức về hàm remember(), trạng thái, chuyển trạng thái lên trên (state hoisting) và sự khác biệt giữa các hàm có khả năng kết hợp có trạng thái và không có trạng thái

Kiến thức bạn sẽ học được

  • Cách thêm nút hành động vào bàn phím ảo.
  • Thành phần kết hợp Switch là gì và cách sử dụng nó.
  • Thêm biểu tượng ở đầu vào trường văn bản.

Sản phẩm bạn sẽ tạo ra

  • Một ứng dụng Tip Time tính số tiền boa dựa trên số tiền trên hoá đơn và tỷ lệ boa mà người dùng nhập.

Bạn cần

2. Lấy đoạn mã khởi đầu

Để bắt đầu, hãy tải mã khởi đầu xuống:

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-tip-calculator.git
$ cd basic-android-kotlin-compose-training-tip-calculator
$ git checkout state

Bạn có thể duyệt xem mã này trong Kho lưu trữ GitHub Tip Time.

3. Tổng quan về ứng dụng ban đầu

Lớp học lập trình này bắt đầu bằng ứng dụng Tip Time trong lớp học lập trình trước (Giới thiệu về trạng thái trong Compose). Ứng dụng này cung cấp giao diện người dùng cần thiết để tính tiền boa với tỷ lệ phần trăm tiền boa cố định. Hộp văn bản Bill amount (Số tiền trên hoá đơn) cho phép người sử dụng nhập chi phí dịch vụ. Ứng dụng sẽ tính toán và hiển thị số tiền boa trong thành phần kết hợp Text.

Chạy ứng dụng Tip Time (Tính tiền boa)

  1. Mở dự án Tip Time trong Android Studio và chạy ứng dụng trên trình mô phỏng hoặc thiết bị.
  2. Nhập số tiền trên hoá đơn. Ứng dụng sẽ tự động tính toán và hiển thị số tiền boa.

b6bd5374911410ac.png

Theo cách tính hiện tại, tỷ lệ phần trăm tiền boa được nhập trực tiếp vào mã nguồn là 15%. Trong lớp học lập trình này, bạn mở rộng tính năng này bằng một trường văn bản để ứng dụng có thể tùy chỉnh tỷ lệ phần trăm tiền boa và làm tròn số tiền boa.

Thêm các tài nguyên chuỗi cần thiết

  1. Trong thẻ Project (Dự án), hãy nhấp vào res > values > strings.xml (tài nguyên > giá trị > strings.xml).
  2. Ở giữa các thẻ <resources> của tệp strings.xml, hãy thêm các tài nguyên chuỗi sau:
<string name="how_was_the_service">Tip Percentage</string>
<string name="round_up_tip">Round up tip?</string>

Tệp strings.xml sẽ có dạng như đoạn mã này, bao gồm cả các chuỗi từ lớp học lập trình trước:

strings.xml

<resources>
    <string name="app_name">Tip Time</string>
    <string name="calculate_tip">Calculate Tip</string>
    <string name="bill_amount">Bill Amount</string>
    <string name="how_was_the_service">Tip Percentage</string>
    <string name="round_up_tip">Round up tip?</string>
    <string name="tip_amount">Tip Amount: %s</string>
</resources>

4. Thêm trường văn bản tip-percentage

Khách hàng có thể muốn boa nhiều hoặc ít hơn tuỳ vào chất lượng dịch vụ họ nhận được và các lý do khác. Để đáp ứng yêu cầu này, ứng dụng phải cho phép người dùng tùy chỉnh số tiền boa. Trong phần này, bạn sẽ thêm một trường văn bản để người dùng nhập phần trăm tiền boa tuỳ chỉnh như trong hình sau:

391b4b1a090687ef.png

Bạn đã có trường văn bản Bill Amount (Số tiền trên hoá đơn) trong ứng dụng, đây là hàm có khả năng kết hợp EditNumberField() không có trạng thái. Trong lớp học lập trình trước, bạn đã đưa trạng thái amountInput từ thành phần kết hợp EditNumberField() vào thành phần kết hợp TipTimeLayout(), điều này khiến thành phần kết hợp EditNumberField() không có trạng thái.

Để thêm một trường văn bản, bạn có thể sử dụng lại thành phần kết hợp EditNumberField(), nhưng với nhãn khác. Để thay đổi như vậy, bạn cần truyền nhãn dưới dạng một tham số, thay vì nhập trực tiếp nhãn này vào trong hàm có khả năng kết hợp EditNumberField().

Giúp hàm có khả năng kết hợp EditNumberField() có thể được tái sử dụng:

  1. Ở tệp MainActivity.kt trong tham số của hàm kết hợp EditNumberField(), hãy thêm tài nguyên chuỗi label thuộc kiểu Int:
@Composable
fun EditNumberField(
    label: Int,
    value: String,
    onValueChanged: (String) -> Unit,
    modifier: Modifier = Modifier
)
  1. Trong phần thân hàm, hãy thay thế mã của tài nguyên chuỗi đã cố định giá trị trong mã bằng tham số label:
@Composable
fun EditNumberField(
    //...
) {
     TextField(
         //...
         label = { Text(stringResource(label)) },
         //...
     )
}
  1. Để biểu thị tham số label được kỳ vọng là tham chiếu tài nguyên chuỗi, hãy chú giải tham số hàm bằng chú thích @StringRes:
@Composable
fun EditNumberField(
    @StringRes label: Int,
    value: String,
    onValueChanged: (String) -> Unit,
    modifier: Modifier = Modifier
)
  1. Nhập các mục sau đây:
import androidx.annotation.StringRes
  1. Trong lệnh gọi hàm EditNumberField() của hàm có khả năng kết hợp TipTimeLayout(), hãy đặt tham số label thành tài nguyên chuỗi R.string.bill_amount:
EditNumberField(
    label = R.string.bill_amount,
    value = amountInput,
    onValueChanged = { amountInput = it },
    modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth()
)
  1. Không thay đổi bất kỳ điều gì đối với hình ảnh trong ngăn Preview (Xem trước).

b223d5ba4a54f792.png

  1. Trong hàm có khả năng kết hợp TipTimeLayout() sau lệnh gọi hàm EditNumberField(), hãy thêm một trường văn bản khác cho tỷ lệ phần trăm tiền boa tuỳ chỉnh. Gọi một hàm có khả năng kết hợp EditNumberField() với các tham số sau:
EditNumberField(
    label = R.string.how_was_the_service,
    value = "",
    onValueChanged = { },
    modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth()
)

Thao tác này sẽ thêm một hộp văn bản khác cho tỷ lệ phần trăm tiền boa tuỳ chỉnh.

  1. Bản xem trước ứng dụng hiện hiển thị trường văn bản Tip Percentage (Phần trăm tiền boa) như trong hình sau:

a5f5ef5e456e185e.png

  1. Ở đầu hàm có khả năng kết hợp TipTimeLayout(), hãy thêm một thuộc tính var có tên là tipInput cho biến trạng thái của trường văn bản đã thêm. Hãy dùng mutableStateOf("") để khởi tạo biến và kết hợp với lệnh gọi bằng hàm remember:
var tipInput by remember { mutableStateOf("") }
  1. Trong lệnh gọi hàm mới EditNumberField(), hãy đặt tham số có tên value thành biến tipInput và sau đó cập nhật biến tipInput trong biểu thức lambda onValueChanged:
EditNumberField(
    label = R.string.how_was_the_service,
    value = tipInput,
    onValueChanged = { tipInput = it },
    modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth()
)
  1. Trong hàm TipTimeLayout() sau định nghĩa biến tipInput. Hãy xác định val có tên là tipPercent sẽ chuyển đổi biến tipInput thành loại Double. Hãy sử dụng toán tử Elvis và trả về 0 nếu giá trị là null. Giá trị này có thể là null nếu trường văn bản trống.
val tipPercent = tipInput.toDoubleOrNull() ?: 0.0
  1. Trong hàm TipTimeLayout(), hãy cập nhật lệnh gọi hàm calculateTip(), truyền biến tipPercent làm tham số thứ hai:
val tip = calculateTip(amount, tipPercent)

Đoạn mã cho hàm TipTimeLayout() sẽ trông giống như sau:

@Composable
fun TipTimeLayout() {
    var amountInput by remember { mutableStateOf("") }
    var tipInput by remember { mutableStateOf("") }
    val amount = amountInput.toDoubleOrNull() ?: 0.0
    val tipPercent = tipInput.toDoubleOrNull() ?: 0.0

    val tip = calculateTip(amount, tipPercent)
    Column(
        modifier = Modifier.padding(40.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(
            text = stringResource(R.string.calculate_tip),
            modifier = Modifier
                .padding(bottom = 16.dp)
                .align(alignment = Alignment.Start)
        )
        EditNumberField(
            label = R.string.bill_amount,
            value = amountInput,
            onValueChanged = { amountInput = it },
            modifier = Modifier
                .padding(bottom = 32.dp)
                .fillMaxWidth()
        )
        EditNumberField(
            label = R.string.how_was_the_service,
            value = tipInput,
            onValueChanged = { tipInput = it },
            modifier = Modifier
                .padding(bottom = 32.dp)
                .fillMaxWidth()
        )
        Text(
            text = stringResource(R.string.tip_amount, tip),
            style = MaterialTheme.typography.displaySmall
        )
        Spacer(modifier = Modifier.height(150.dp))
    }
}
  1. Chạy ứng dụng trên trình mô phỏng hoặc thiết bị, sau đó nhập số tiền trên hóa đơn và tỷ lệ phần trăm tiền boa. Ứng dụng có tính đúng số tiền boa không?

ảnh chụp màn hình với bill amount (số tiền trên hoá đơn) là 100, tip percentage (tỷ lệ phần trăm tiền boa) là 20 và tip amount (số tiền boa) là 20 đô la

5. Đặt nút hành động

Trong lớp học lập trình trước, bạn đã tìm hiểu cách dùng lớp KeyboardOptions để cài đặt loại bàn phím. Trong phần này, bạn sẽ tìm hiểu cách thiết lập nút hành động trên bàn phím cũng với KeyboardOptions. Nút hành động trên bàn phím là nút nằm dưới cùng bàn phím. Bạn có thể thấy một số ví dụ trong bảng này:

Thuộc tính

Nút hành động trên bàn phím

ImeAction.Search
Được sử dụng khi người dùng muốn tìm kiếm.

Hình ảnh này biểu thị biểu tượng Tìm kiếm để thực hiện một lượt tìm kiếm.

ImeAction.Send
Được sử dụng khi người dùng muốn gửi văn bản trong trường nhập dữ liệu.

Hình ảnh này biểu thị biểu tượng Gửi để gửi văn bản trong trường nhập dữ liệu.

ImeAction.Go
Được sử dụng khi người dùng muốn chuyển đến mục tiêu của văn bản trong mục nhập.

Hình ảnh này biểu thị biểu tượng Di chuyển để chuyển đến mục tiêu của văn bản trong mục nhập.

Trong tác vụ này, bạn cài đặt 2 nút hành động khác nhau cho các hộp văn bản:

  • Nút hành động Next (Tiếp theo) cho hộp văn bản Bill Amount (Số tiền hoá đơn), cho biết người dùng hiện đã hoàn thành thao tác nhập và muốn chuyển sang hộp văn bản tiếp theo.
  • Nút hành động Done (Xong) cho hộp văn bản Tip Percentage (phần trăm tiền boa) cho biết người dùng đã nhập xong thông tin đầu vào.

Bạn có thể xem ví dụ về bàn phím với các nút hành động trong các hình sau:

Thêm tuỳ chọn bàn phím:

  1. Trong lệnh gọi hàm TextField() của hàm EditNumberField(), hãy truyền hàm khởi tạo KeyboardOptions, một đối số có tên imeAction được đặt thành giá trị ImeAction.Next. Sử dụng hàm KeyboardOptions.Default.copy() để đảm bảo bạn sử dụng các lựa chọn mặc định khác.
import androidx.compose.ui.text.input.ImeAction

@Composable
fun EditNumberField(
    //...
) {
    TextField(
        //...
        keyboardOptions = KeyboardOptions.Default.copy(
            keyboardType = KeyboardType.Number,
            imeAction = ImeAction.Next
        )
    )
}
  1. Chạy ứng dụng trên trình mô phỏng hoặc thiết bị. Giờ đây, bàn phím hiển thị nút hành động Tiếp theo như có thể thấy trong hình sau:

82574a95b658f052.png

Lưu ý rằng bàn phím hiển thị cùng nút hành động Tiếp theo khi chọn trường văn bản Tip Percentage (Phần trăm tiền boa). Tuy nhiên, bạn cần 2 nút hành động khác nhau cho các trường văn bản. Bạn sẽ sớm khắc phục được vấn đề này.

  1. Kiểm tra hàm EditNumberField(). Tham số keyboardOptions trong hàm TextField() được mã hóa cứng. Để tạo những nút hành động khác cho các trường văn bản, bạn cần truyền đối tượng KeyboardOptions dưới dạng một đối số. Đây là việc bạn sẽ thực hiện trong bước tiếp theo.
// No need to copy, just examine the code.
fun EditNumberField(
    @StringRes label: Int,
    value: String,
    onValueChanged: (String) -> Unit,
    modifier: Modifier = Modifier
) {
    TextField(
        //...
        keyboardOptions = KeyboardOptions.Default.copy(
           keyboardType = KeyboardType.Number,
           imeAction = ImeAction.Next
        )
    )
}
  1. Trong định nghĩa hàm EditNumberField(), hãy thêm một tham số keyboardOptions thuộc loại KeyboardOptions. Trong phần nội dung hàm, hãy chỉ định hàm này vào tham số có tên keyboardOptions của hàm TextField():
@Composable
fun EditNumberField(
    @StringRes label: Int,
    keyboardOptions: KeyboardOptions,
    // ...
){
    TextField(
        //...
        keyboardOptions = keyboardOptions
    )
}
  1. Trong hàm TipTimeLayout(), hãy cập nhật lệnh gọi hàm EditNumberField() đầu tiên, truyền tham số có tên keyboardOptions vào trường văn bản Bill Amount (Số tiền trên hoá đơn):
EditNumberField(
    label = R.string.bill_amount,
    keyboardOptions = KeyboardOptions.Default.copy(
        keyboardType = KeyboardType.Number,
        imeAction = ImeAction.Next
    ),
    // ...
)
  1. Ở lệnh gọi hàm thứ hai EditNumberField(), thay đổi phần trăm tiền boa của trường văn bảnimeAction thành ImeAction.Done. Hàm của bạn phải trông giống như đoạn mã sau:
EditNumberField(
    label = R.string.how_was_the_service,
    keyboardOptions = KeyboardOptions.Default.copy(
        keyboardType = KeyboardType.Number,
        imeAction = ImeAction.Done
    ),
    // ...
)
  1. Chạy ứng dụng. Thành phần này hiển thị các nút hành động Tiếp theoXong như có thể thấy trong các hình sau:

  1. Nhập số tiền trên hoá đơn bất kỳ và nhấp vào nút hành động Tiếp theo, sau đó nhập tỷ lệ phần trăm tiền boa bất kỳ rồi nhấp vào nút hành động Xong. Thao tác đó sẽ đóng bàn phím.

a9e3fbddfff829c8.gif

6. Thêm một nút chuyển

Nút chuyển có trạng thái bật/tắt của một mục.

6923dfb1101602c7.png

Nút bật/tắt có hai trạng thái cho phép người dùng chọn giữa hai 2 lựa chọn. Một nút bật/tắt có 2 phần thumb và track cùng với một biểu tượng tuỳ ý như trong các hình sau:

b4f7f68b848bcc2b.png

Nút chuyển là một lựa chọn kiểm soát có thể được dùng để nhập quyết định hoặc khai báo tuỳ chọn, chẳng hạn như các chế độ cài đặt bạn có thể thấy trong hình sau:

5cd8acb912ab38eb.png

Người dùng có thể kéo nút thumb qua lại để đánh dấu lựa chọn hoặc chỉ cần nhấn vào nút chuyển để bật/tắt. Bạn có thể xem một ví dụ khác về nút bật/tắt trong ảnh GIF này, trong đó chế độ cài đặt Visual options (Tuỳ chọn hiển thị) được chuyển thành Dark mode (Chế độ tối):

eabf96ad496fd226.gif

Để tìm hiểu thêm về nút chuyển, hãy tìm đọc tài liệu về Nút chuyển.

Bạn sử dụng thành phần kết hợp Switch để người dùng có thể chọn làm tròn số tiền boa lên số nguyên gần nhất như có thể thấy trong hình sau:

b42af9f2d3861e4.png

Thêm một hàng cho thành phần kết hợp TextSwitch:

  1. Sau hàm EditNumberField(), hãy thêm một hàm có khả năng kết hợp RoundTheTipRow() rồi truyền một Modifier mặc định làm đối số tương tự như hàm EditNumberField():
@Composable
fun RoundTheTipRow(modifier: Modifier = Modifier) {
}
  1. Triển khai hàm RoundTheTipRow(), thêm một thành phần kết hợp bố cục Row với modifier sau đây để đặt chiều rộng của các thành phần con thành mức tối đa trên màn hình, căn giữa và đảm bảo kích thước là 48dp :
Row(
   modifier = modifier
       .fillMaxWidth()
       .size(48.dp),
   verticalAlignment = Alignment.CenterVertically
) {
}
  1. Nhập các mục sau đây:
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
  1. Trong khối lambda của bố cục thành phần kết hợp Row, hãy thêm một thành phần kết hợp Text sử dụng tài nguyên chuỗi R.string.round_up_tip để hiển thị một chuỗi Round up tip?:
Text(text = stringResource(R.string.round_up_tip))
  1. Sau thành phần kết hợp Text, hãy thêm một thành phần kết hợp Switch và truyền tham số có tên checked được đặt thành roundUp và một tham số có tên onCheckedChange được đặt thành onRoundUpChanged.
Switch(
    checked = roundUp,
    onCheckedChange = onRoundUpChanged,
)

Bảng này chứa thông tin về các tham số bạn đã xác định cho hàm RoundTheTipRow():

Tham số

Mô tả

checked

Liệu nút chuyển này có được kiểm tra hay không. Đây là trạng thái của thành phần kết hợp Switch.

onCheckedChange

Lệnh gọi lại sẽ được gọi khi nút chuyển được nhấp.

  1. Nhập các mục sau đây:
import androidx.compose.material3.Switch
  1. Trong hàm RoundTheTipRow(), hãy thêm tham số roundUp thuộc loại Boolean và hàm lambda onRoundUpChanged nhận Boolean và không trả về giá trị nào:
@Composable
fun RoundTheTipRow(
    roundUp: Boolean,
    onRoundUpChanged: (Boolean) -> Unit,
    modifier: Modifier = Modifier
)

Việc này sẽ chuyển trạng thái của nút chuyển.

  1. Trong thành phần kết hợp Switch, hãy thêm modifier này để căn chỉnh thành phần kết hợp Switch đến cuối màn hình:
       Switch(
           modifier = modifier
               .fillMaxWidth()
               .wrapContentWidth(Alignment.End),
           //...
       )
  1. Nhập các mục sau đây:
import androidx.compose.foundation.layout.wrapContentWidth
  1. Trong hàm TipTimeLayout(), hãy thêm một biến var cho trạng thái của thành phần kết hợp Switch. Tạo một biến var có tên là roundUp, đặt biến đó thành mutableStateOf(), trong đó false là giá trị ban đầu. Bao quanh lệnh gọi bằng remember { }.
fun TipTimeLayout() {
    //...
    var roundUp by remember { mutableStateOf(false) }

    //...
    Column(
        ...
    ) {
      //...
   }
}

Đây là biến cho trạng thái thành phần kết hợp Switch và false sẽ là trạng thái mặc định.

  1. Trong khối TipTimeLayout() của hàm Column sau trường văn bản Tip Percentage (Phần trăm tiền boa), hãy gọi hàm RoundTheTipRow() với các đối số sau: tham số có tên roundUp được đặt thành roundUp và tham số có tên onRoundUpChanged được đặt thành lệnh gọi lại lambda cập nhật giá trị roundUp:
@Composable
fun TipTimeLayout() {
    //...

    Column(
        ...
    ) {
        Text(
            ...
        )
        Spacer(...)
        EditNumberField(
            ...
        )
        EditNumberField(
            ...
        )
        RoundTheTipRow(
             roundUp = roundUp,
             onRoundUpChanged = { roundUp = it },
             modifier = Modifier.padding(bottom = 32.dp)
         )
        Text(
            ...
        )
    }
}

Thao tác này sẽ hiển thị hàng Round up tip? (Làm tròn tiền boa?).

  1. Chạy ứng dụng. Ứng dụng sẽ hiển thị nút bật/tắt Round up tip (Làm tròn tiền boa).

5225395a29022a5e.png

  1. Nhập số tiền trên hoá đơn và tỷ lệ phần trăm của tiền boa, sau đó chọn nút bật/tắt Round up tip? (Làm tròn tiền boa?). Số tiền boa sẽ không được làm tròn vì bạn vẫn cần phải cập nhật hàm calculateTip() trong phần tiếp theo.

Cập nhật hàm calculateTip() để làm tròn tiền boa

Sửa đổi hàm calculateTip() để chấp nhận biến Boolean nhằm làm tròn tiền boa lên số nguyên gần nhất:

  1. Để làm tròn tiền boa, hàm calculateTip() phải biết trạng thái của nút chuyển, đó là Boolean. Trong hàm calculateTip(), hãy thêm tham số roundUp thuộc loại Boolean:
private fun calculateTip(
    amount: Double,
    tipPercent: Double = 15.0,
    roundUp: Boolean
): String {
    //...
}
  1. Trong hàm calculateTip() trước câu lệnh return, hãy thêm một điều kiện if() kiểm tra giá trị roundUp. Nếu roundUptrue, hãy xác định một biến tip rồi đặt thành hàm kotlin.math.ceil() rồi truyền hàm đó với tip làm đối số:
if (roundUp) {
    tip = kotlin.math.ceil(tip)
}

Hàm calculateTip() hoàn chỉnh sẽ có dạng như đoạn mã dưới đây:

private fun calculateTip(amount: Double, tipPercent: Double = 15.0, roundUp: Boolean): String {
    var tip = tipPercent / 100 * amount
    if (roundUp) {
        tip = kotlin.math.ceil(tip)
    }
    return NumberFormat.getCurrencyInstance().format(tip)
}
  1. Trong hàm TipTimeLayout(), hãy cập nhật lệnh gọi hàm calculateTip() rồi truyền một tham số roundUp:
val tip = calculateTip(amount, tipPercent, roundUp)
  1. Chạy ứng dụng. Giờ đây, nó sẽ làm tròn số tiền boa như bạn thấy ở những hình sau:

7. Thêm tuỳ chọn hỗ trợ cho hướng ngang

Thiết bị Android có nhiều kiểu dáng, bao gồm điện thoại, máy tính bảng, thiết bị có thể gập lại và thiết bị ChromeOS, với nhiều kích thước màn hình. Ứng dụng của bạn phải hỗ trợ cả hướng dọc và ngang.

  1. Kiểm thử ứng dụng ở chế độ ngang, bật chế độ Tự động xoay.

8566fc367d5a5b2f.png

  1. Xoay trình mô phỏng hoặc thiết bị sang trái, để ý bạn sẽ không thấy số tiền boa. Để giải quyết vấn đề này, bạn cần có một thanh cuộn dọc để cuộn màn hình ứng dụng.

28d23a73c2a5ea24.png

  1. Thêm .verticalScroll(rememberScrollState()) vào đối tượng sửa đổi để cho phép cột có thể cuộn theo chiều dọc. rememberScrollState() tạo và tự động ghi nhớ trạng thái cuộn.
@Composable
fun TipTimeLayout() {
    // ...
    Column(
        modifier = Modifier
            .padding(40.dp)
            .verticalScroll(rememberScrollState()),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        //...
    }
}
  1. Nhập các mục sau đây:
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
  1. Chạy lại ứng dụng. Hãy thử cuộn ở chế độ ngang!

179866a0fae00401.gif

8. Thêm biểu tượng ở đầu vào trường văn bản (không bắt buộc)

Các biểu tượng có thể làm cho trường văn bản trở nên hấp dẫn hơn và cung cấp thêm thông tin về trường văn bản đó. Có thể sử dụng các biểu tượng để truyền đạt thông tin về mục đích của trường văn bản, chẳng hạn như loại dữ liệu dự kiến hoặc loại dữ liệu đầu vào được yêu cầu. Ví dụ: biểu tượng điện thoại bên cạnh trường văn bản có thể cho biết người dùng cần nhập số điện thoại.

Có thể sử dụng các biểu tượng để định hướng hoạt động đầu vào của người dùng bằng cách đưa ra chỉ dẫn bằng hình ảnh về những gì sẽ xảy ra tiếp theo. Ví dụ: biểu tượng lịch bên cạnh trường văn bản có thể cho người dùng biết sẽ phải nhập ngày tháng.

Sau đây là ví dụ về trường văn bản kèm theo biểu tượng tìm kiếm, cho bạn biết phải nhập cụm từ tìm kiếm ở trường này.

9318c9a2414c4add.png

Thêm một tham số khác vào thành phần kết hợp EditNumberField() có tên là leadingIcon thuộc loại Int. Chú thích hàm này bằng @DrawableRes.

@Composable
fun EditNumberField(
    @StringRes label: Int,
    @DrawableRes leadingIcon: Int,
    keyboardOptions: KeyboardOptions,
    value: String,
    onValueChanged: (String) -> Unit,
    modifier: Modifier = Modifier
)
  1. Nhập các mục sau đây:
import androidx.annotation.DrawableRes
import androidx.compose.material3.Icon
  1. Thêm biểu tượng ở đầu vào trường văn bản. leadingIcon nhận một thành phần kết hợp, bạn sẽ truyền thành phần kết hợp Icon sau.
TextField(
    value = value,
    leadingIcon = { Icon(painter = painterResource(id = leadingIcon), null) },
    //...
)
  1. Chuyển biểu tượng ở đầu vào trường văn bản. Các biểu tượng đã có sẵn trong mã nguồn khởi đầu để thuận tiện cho bạn.
EditNumberField(
    label = R.string.bill_amount,
    leadingIcon = R.drawable.money,
    // Other arguments
)
EditNumberField(
    label = R.string.how_was_the_service,
    leadingIcon = R.drawable.percent,
    // Other arguments
)
  1. Chạy ứng dụng.

bff007b9d67ede83.png

Xin chúc mừng! Ứng dụng của bạn hiện có khả năng tính toán số tiền boa tuỳ chỉnh.

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

Để tải xuống mã cho lớp học lập trình đã kết thúc, bạn có thể sử dụng lệnh git này:

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

Ngoài ra, bạn có thể tải kho lưu trữ xuống dưới dạng tệp zip, sau đó giải nén và mở tệp đó trong Android Studio.

Nếu bạn muốn xem mã giải pháp, hãy xem mã đó trên GitHub.

10. Kết luận

Xin chúc mừng! Bạn đã thêm chức năng tiền boa tuỳ chỉnh vào ứng dụng Tip Time của mình. Giờ đây, ứng dụng cho phép người dùng nhập một tỷ lệ phần trăm tiền boa tuỳ chỉnh và làm tròn số tiền boa đó. Chia sẻ thành quả của bạn lên mạng xã hội với hashtag #AndroidBasics!

Tìm hiểu thêm