Tạo ứng dụng đơn giản với thành phần kết hợp văn bản

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

Trong lớp học lập trình này, bạn sẽ sử dụng Jetpack Compose để tạo một ứng dụng Android đơn giản nhằm hiển thị lời chúc mừng sinh nhật trên màn hình.

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

  • Biết cách tạo ứng dụng trong Android Studio.
  • Biết cách chạy ứng dụng trên trình mô phỏng hoặc thiết bị Android.

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

  • Cách viết các hàm có khả năng kết hợp, chẳng hạn như các hàm Text, ColumnRow.
  • Cách hiển thị văn bản trong ứng dụng theo bố cục.
  • Cách định dạng văn bản, chẳng hạn như thay đổi kích thước văn bản.

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

  • Ứng dụng Android hiển thị lời chào sinh nhật ở định dạng văn bản như ảnh chụp màn hình này khi hoàn tất:

fdf3fc55ab1d348a.png

Bạn cần có

  • Máy tính đã cài đặt Android Studio

2. Thiết lập ứng dụng Happy Birthday

Trong nhiệm vụ này, bạn sẽ thiết lập một dự án trong Android Studio thông qua mẫu Empty Activity (Hoạt động trống) và thay đổi thông điệp văn bản thành lời chào sinh nhật được cá nhân hoá.

Tạo dự án Hoạt động trống

  1. Trong hộp thoại Welcome to Android Studio (Chào mừng bạn đến với Android Studio), hãy chọn New Project (Dự án mới).
  2. Trong hộp thoại New Project (Dự án mới), hãy chọn Empty Activity (Hoạt động trống) rồi nhấp vào Next (Tiếp theo).
  3. Trong trường Name (Tên), hãy nhập Happy Birthday rồi chọn mức API tối thiểu là 24 (Nougat) trong trường Minimum SDK (SDK tối thiểu) và nhấp vào Finish (Hoàn tất).

ff60c8aef54e55e5.png

  1. Chờ Android Studio tạo các tệp dự án và xây dựng dự án.
  2. Nhấp vào fd26b2e3c2870c3.png Run ‘app' (Chạy "ứng dụng").

Ứng dụng sẽ có dạng như ảnh chụp màn hình sau:

51ca4dec519ee45c.png

Khi tạo ứng dụng Happy Birthday này bằng mẫu Empty Activity (Hoạt động trống), Android Studio sẽ thiết lập tài nguyên cho ứng dụng Android cơ bản, bao gồm thông báo Hello Android! (Xin chào Android!) trên màn hình. Trong lớp học lập trình này, bạn tìm hiểu cách hiển thị thông báo này, cách thay đổi văn bản thành lời chào sinh nhật, cũng như cách thêm và định dạng các thông báo bổ sung.

Giao diện người dùng (UI) là gì?

Giao diện người dùng (UI) của một ứng dụng là những gì bạn nhìn thấy trên màn hình: văn bản, hình ảnh, nút lệnh cũng như nhiều thành phần khác và bố cục hiển thị của các thành phần này. Đó là cách ứng dụng hiển thị nội dung cho người dùng và cách người dùng tương tác với ứng dụng.

Hình ảnh này chứa nút có thể nhấp, thông điệp văn bản và trường nhập dữ liệu văn bản để người dùng có thể nhập dữ liệu.

cb6997dfd11668c4.png

Nút có thể nhấp

50a9b402fd9037c0.png

Tin nhắn văn bản bên trong một Thẻ

17794ea52cfb5473.png

Trường nhập dữ liệu văn bản

Mỗi phần tử trong số này được gọi là một thành phần giao diện người dùng. Hầu hết những gì bạn thấy trên màn hình của ứng dụng đều là thành phần trên giao diện người dùng (còn được gọi là thành phần giao diện người dùng). Đây là những thành phần có khả năng tương tác, như nút có khả năng nhấp hoặc trường nhập dữ liệu có thể chỉnh sửa hoặc có thể là hình ảnh trang trí.

Trong các ứng dụng sau, hãy cố gắng tìm càng nhiều phần tử trên giao diện người dùng càng tốt.

đang hiện các ứng dụng được đề xuất

Trong lớp học lập trình này, bạn sẽ làm việc với một phần tử trên giao diện người dùng để hiển thị văn bản có tên là phần tử Text.

3. Jetpack Compose là gì?

Jetpack Compose là một bộ công cụ hiện đại giúp xây dựng giao diện người dùng cho Android. Compose giúp đơn giản hoá và tăng tốc quá trình phát triển giao diện người dùng trên Android nhờ dùng ít mã hơn, các công cụ mạnh mẽ và khả năng triển khai trực quan. Với Compose, bạn có thể xây dựng giao diện người dùng bằng cách định nghĩa tập hợp các hàm, đây là hàm có khả năng kết hợp, cho phép lấy dữ liệu và mô tả các phần tử trên giao diện người dùng.

Hàm có khả năng kết hợp

Các hàm có khả năng kết hợp là thành phần xây dựng giao diện người dùng cơ bản trong Compose. Hàm có khả năng kết hợp:

  • Mô tả một số thành phần trên giao diện người dùng.
  • Không trả về giá trị.
  • Lấy giá trị đầu vào và tạo nội dung hiện trên màn hình.

Chú giải

Chú thích là phương tiện để thêm thông tin bổ sung vào mã. Thông tin này giúp các công cụ như trình biên dịch Jetpack Compose và các nhà phát triển khác hiểu được mã của ứng dụng.

Bạn có thể áp dụng chú thích bằng cách thêm tiền tố chú thích chứa ký tự @ ở đầu phần khai báo. Bạn có thể chú thích các thành phần mã khác nhau, bao gồm thuộc tính, hàm và lớp. Trong phần sau của khoá học, bạn sẽ tìm hiểu thêm về lớp.

Biểu đồ dưới đây là một ví dụ về hàm có chú giải:

Biểu đồ cho thấy cấu trúc của một hàm có khả năng kết hợp, trong đó ký tự @ trong tiền tố chú thích là thành phần kết hợp, theo sau là phần khai báo hàm.

Đoạn mã sau đây cung cấp các ví dụ về thuộc tính có chú giải. Bạn sẽ dùng tính năng này trong các lớp học lập trình sắp tới.

// Example code, do not copy it over

@Json
val imgSrcUrl: String

@Volatile
private var INSTANCE: AppDatabase? = null

Chú thích chứa tham số

Chú thích có thể chứa các tham số. Các tham số sẽ cung cấp thêm thông tin cho các công cụ trong quá trình xử lý. Sau đây là một số ví dụ về chú thích @Preview có và không có tham số.

Ảnh chụp màn hình Android Studio cho thấy mã và bản xem trước

Chú thích không chứa tham số

Ảnh chụp màn hình Android Studio cho thấy mã và bản xem trước

Chú thích xem trước phần nền

Ảnh chụp màn hình Android Studio cho thấy mã và bản xem trước

Chú giải chứa tiêu đề xem trước

Bạn có thể truyền nhiều đối số vào chú giải, như minh hoạ dưới đây.

fd2ad3c2e7c8a9c7.png

Chú thích chứa tiêu đề xem trước và giao diện người dùng hệ thống (màn hình điện thoại)

Jetpack Compose sử dụng nhiều chú thích được tích hợp sẵn. Đến thời điểm này, bạn đã xem qua các chú thích @Composable@Preview trong khoá học này. Bạn sẽ tìm hiểu thêm về chú thích và cách sử dụng trong phần sau của khoá học.

Ví dụ về hàm có khả năng kết hợp

Bạn có thể chú thích cho hàm có khả năng kết hợp bằng cách sử dụng chú thích @Composable. Tất cả hàm có khả năng kết hợp phải dùng chú thích này. Chú thích này sẽ thông báo cho trình biên dịch Compose biết rằng hàm này sẽ giúp chuyển đổi dữ liệu thành giao diện người dùng. Lưu ý rằng trình biên dịch là một chương trình đặc biệt có chức năng lấy mã bạn viết, duyệt mã theo từng dòng rồi dịch mã này dưới dạng thông tin mà máy tính có thể hiểu được (ngôn ngữ máy).

Đoạn mã này là một ví dụ về một hàm có khả năng kết hợp đơn giản dùng để truyền dữ liệu (là tham số name) và sử dụng đoạn mã này để hiển thị thành phần văn bản trên màn hình.

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

Một số lưu ý về hàm có khả năng kết hợp:

  • Jetpack Compose được xây dựng xung quanh các hàm có khả năng kết hợp. Các hàm này cho phép bạn xác định giao diện người dùng của ứng dụng theo cách lập trình bằng việc mô tả giao diện đó, thay vì tập trung vào quy trình xây dựng giao diện người dùng. Để tạo một hàm có khả năng kết hợp, chỉ cần thêm chú giải @Composable vào tên hàm.
  • Các hàm có khả năng kết hợp có thể chấp nhận các đối số, cho phép triển khai logic ứng dụng để mô tả hoặc chỉnh sửa giao diện người dùng. Trong trường hợp này, phần tử trên giao diện người dùng sẽ chấp nhận một String để có thể kèm tên người dùng trong lời chào.

Lưu ý về hàm có khả năng kết hợp trong mã

  1. Trong Android Studio, mở tệp MainActivity.kt.
  2. Di chuyển đến hàm GreetingPreview(). Hàm có khả năng kết hợp này giúp bạn xem trước hàm Greeting(). Bạn có thể áp dụng một phương pháp hay khi đặt tên hoặc đổi tên hàm là luôn dùng tên hàm mang tính gợi tả về chức năng hoạt động của hàm đó. Hãy đổi tên hàm này thành BirthdayCardPreview().
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
    HappyBirthdayTheme {
        Greeting("Android")
    }
}

Hàm có khả năng kết hợp có thể gọi đến các hàm có khả năng kết hợp khác. Trong đoạn mã này, hàm xem trước đang gọi đến hàm có khả năng kết hợp Greeting().

Lưu ý rằng hàm trước đó cũng có một chú thích khác, chú thích @Preview, có chứa một tham số đặt trước chú thích @Composable. Bạn có thể tìm hiểu thêm về các đối số được truyền đến chú thích @Preview trong phần sau của khóa học này.

Tên hàm có khả năng kết hợp

Hàm có khả năng kết hợp không trả về giá trị nào và có chú giải @Composable PHẢI được đặt tên theo kiểu viết hoa Pascal. Kiểu viết hoa Pascal là một quy ước đặt tên, trong đó chữ cái đầu của mỗi từ trong từ ghép phải được viết hoa. Sự khác biệt giữa kiểu viết hoa Pascal và kiểu viết lạc đà là tất cả từ trong kiểu Pascal đều phải viết hoa chữ cái đầu tiên. Trong kiểu viết lạc đà, từ đầu tiên có thể ở cả hai trường hợp.

Hàm có khả năng kết hợp:

  • PHẢI là danh từ: DoneButton()
  • KHÔNG phải động từ hoặc cụm động từ: DrawTextField()
  • KHÔNG phải là giới từ theo sau danh từ: TextFieldWithLink()
  • KHÔNG phải là tính từ: Bright()
  • KHÔNG phải là trạng từ: Outside()
  • Danh từ CÓ THỂ đứng trước tính từ mô tả: RoundIcon()

Để tìm hiểu thêm, hãy xem Đặt tên hàm có khả năng kết hợp.

Mã ví dụ Đừng sao chép

// Do: This function is a descriptive PascalCased noun as a visual UI element
@Composable
fun FancyButton(text: String) {}

// Do: This function is a descriptive PascalCased noun as a non-visual element
// with presence in the composition
@Composable
fun BackButtonHandler() {}

// Don't: This function is a noun but is not PascalCased!
@Composable
fun fancyButton(text: String) {}

// Don't: This function is PascalCased but is not a noun!
@Composable
fun RenderFancyButton(text: String) {}

// Don't: This function is neither PascalCased nor a noun!
@Composable
fun drawProfileImage(image: ImageAsset) {}

4. Ngăn thiết kế trong Android Studio

Android Studio cho phép bạn xem trước các hàm có khả năng kết hợp trong IDE thay vì cài đặt ứng dụng trên một thiết bị Android hoặc trình mô phỏng. Như đã tìm hiểu trong lộ trình trước đó, bạn có thể xem trước giao diện của ứng dụng trong ngăn Design (Thiết kế) trên Android Studio.

c284448a820d577c.png

Hàm có khả năng kết hợp phải cung cấp giá trị mặc định của tất cả tham số để có thể xem trước hàm đó. Vì lý do này, bạn không nên xem trước hàm Greeting() trực tiếp. Thay vào đó, trong trường hợp này, bạn cần thêm một hàm BirthdayCardPreview() khác. Hàm này sẽ gọi hàm Greeting() với một tham số phù hợp.

@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
    HappyBirthdayTheme {
        Greeting("Android")
    }
}

Cách xem bản xem trước:

  1. Trong hàm BirthdayCardPreview(), hãy thay đổi đối số "Android" trong hàm Greeting() thành tên của bạn.
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
    HappyBirthdayTheme {
        Greeting("James")
    }
}
  1. Tạo bản dựng mã của bạn. Bản xem trước sẽ tự động cập nhật.

Bạn sẽ thấy bản xem trước được cập nhật.

a9d045e42c47ca1b.png

5. Thêm một phần tử văn bản mới

Trong nhiệm vụ này, bạn xóa lời chào Hello $name! và thêm lời chúc mừng sinh nhật.

Thêm hàm có khả năng kết hợp mới

  1. Trong tệp MainActivity.kt, hãy xóa phần định nghĩa hàm Greeting(). Bạn sẽ thêm hàm của riêng mình để hiển thị lời chúc trong lớp học lập trình sau này.

Xoá mã sau

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(
        text = "Hello $name!",
        modifier = modifier
    )
}
  1. Bên trong hàm onCreate(), hãy lưu ý rằng lệnh gọi hàm Greeting() hiện có màu đỏ. Điều này cho thấy đã xảy ra lỗi. Di chuột qua lệnh gọi hàm này và Android Studio sẽ hiển thị thông tin về lỗi.

f5635be4356320a7.png

  1. Xoá lệnh gọi hàm Greeting() cùng các đối số của hàm này từ các hàm onCreate()BirthdayCardPreview(). Tệp MainActivity.kt của bạn sẽ giống như sau:
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            HappyBirthdayTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                }
            }
        }
    }
}

@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
    HappyBirthdayTheme {
    }
}
  1. Trước hàm BirthdayCardPreview(), thêm một hàm mới tên là GreetingText(). Đừng quên thêm chú giải @Composable trước hàm này vì đây là một hàm có khả năng kết hợp dùng để mô tả một thành phần kết hợp Text.
@Composable
fun GreetingText() {
}
  1. Phương pháp hay nhất là để Thành phần kết hợp chấp nhận tham số Modifier và truyền modifier đó đến phần tử con đầu tiên của nó. Bạn sẽ tìm hiểu thêm về Modifier và các phần tử con trong các nhiệm vụ và lớp học lập trình tiếp theo. Bây giờ, hãy thêm tham số Modifier vào hàm GreetingText().
@Composable
fun GreetingText(modifier: Modifier = Modifier) {
}
  1. Thêm tham số message có kiểu String vào hàm có khả năng kết hợp GreetingText().
@Composable
fun GreetingText(message: String, modifier: Modifier = Modifier) {
}
  1. Trong hàm GreetingText(), thêm một thành phần kết hợp Text, truyền vào một thông điệp văn bản dưới dạng đối số được đặt tên.
@Composable
fun GreetingText(message: String, modifier: Modifier = Modifier) {
    Text(
        text = message
    )
}

Hàm GreetingText() này sẽ hiển thị văn bản trên giao diện người dùng. Để thực hiện điều đó, hàm này sẽ gọi đến hàm có khả năng kết hợp Text().

Xem trước hàm

Trong nhiệm vụ này, bạn sẽ xem trước hàm GreetingText() trong ngăn Design (Thiết kế).

  1. Gọi hàm GreetingText() bên trong hàm BirthdayCardPreview().
  2. Truyền một đối số String đến hàm GreetingText(). Đây là một lời chào sinh nhật gửi đến bạn bè của bạn. Nếu muốn thì bạn có thể chỉnh lại lời chào theo tên bạn bè của mình, chẳng hạn như "Happy Birthday Sam!".
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
    HappyBirthdayTheme {
        GreetingText(message = "Happy Birthday Sam!")
    }
}
  1. Ngăn Design (Thiết kế) sẽ tự động cập nhật. Xem trước các thay đổi.

fd1260ace2f0f7b0.png

6. Thay đổi kích thước phông chữ

Bạn đã thêm văn bản vào giao diện người dùng, nhưng văn bản này có vẻ chưa giống hoàn toàn với ứng dụng cuối cùng. Trong nhiệm vụ này, bạn tìm hiểu cách thay đổi kích thước, màu sắc văn bản và các thuộc tính khác ảnh hưởng đến hình thức hiển thị của thành phần văn bản. Bạn có thể thử nghiệm các màu sắc và kích thước phông chữ khác nhau.

Pixel có khả năng mở rộng

Các pixel có khả năng mở rộng (SP) là một đơn vị đo kích thước phông chữ. Các thành phần trên giao diện người dùng trong ứng dụng Android sử dụng hai đơn vị đo lường khác nhau: pixel không phụ thuộc vào mật độ (DP), bạn sẽ dùng sau này cho phần bố cục, và pixel có khả năng mở rộng (SP). Theo mặc định, đơn vị SP có cùng kích thước với đơn vị DP, nhưng đơn vị này đổi kích thước dựa trên kích thước văn bản yêu thích của người dùng trong phần cài đặt của điện thoại.

  1. Trong tệp MainActivity.kt, di chuyển đến thành phần kết hợp Text() trong hàm GreetingText().
  2. Truyền vào hàm Text() một đối số fontSize làm đối số được đặt tên thứ hai và thiết lập giá trị cho đối số đó thành 100.sp.
Text(
    text = message,
    fontSize = 100.sp
)

Android Studio sẽ làm nổi bật mã .sp vì bạn cần nhập một số lớp hoặc thuộc tính để biên dịch ứng dụng.

8032c2d4926903d5.png

  1. Nhấp vào mã .sp được Android Studio làm nổi bật ở trên.
  2. Nhấp vào Nhập trong cửa sổ bật lên để nhập androidx.compose.ui.unit.sp nhằm sử dụng thuộc tính mở rộng .sp.
  1. Di chuyển lên đầu tệp và chú ý các câu lệnh import, trong đó bạn sẽ thấy câu lệnh import androidx.compose.ui.unit.sp. Điều này có nghĩa là Android Studio sẽ thêm gói này vào tệp.

e073e9d3465e080c.png

  1. Lưu ý phần thay đổi kích thước phông chữ trong bản xem trước đã cập nhật. Bạn cần chỉ định chiều cao dòng để giải quyết lý do khiến thông điệp bị chồng chéo.

b001a2c51b985d0.png

  1. Cập nhật thành phần kết hợp Text để thêm chiều cao dòng.
@Composable
fun GreetingText(message: String, modifier: Modifier = Modifier) {
    Text(
        text = message,
        fontSize = 100.sp,
        lineHeight = 116.sp,
    )
}

cefc09e773d1f29a.png

Bây giờ, bạn có thể thử nghiệm với các kích thước phông chữ khác nhau.

7. Thêm một phần tử văn bản khác

Trong các nhiệm vụ trước, bạn đã thêm thông điệp chúc mừng sinh nhật cho bạn bè của mình. Trong nhiệm vụ này, bạn sẽ ký tên mình vào thiệp sinh nhật.

  1. Trong tệp MainActivity.kt, di chuyển đến hàm GreetingText().
  2. Truyền vào hàm này tham số from có kiểu String cho phần chữ ký của bạn.
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier)
  1. Sau thành phần kết hợp Text dành cho thông điệp sinh nhật, thêm một thành phần kết hợp Text khác chấp nhận đối số text được đặt thành giá trị from.
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
    Text(
        // ...
    )
    Text(
        text = from
    )
}
  1. Thêm đối số có tên fontSize và đặt giá trị là 36.sp.
Text(
    text = from,
    fontSize = 36.sp
)
  1. Di chuyển đến hàm BirthdayCardPreview().
  2. Thêm một đối số String khác dùng để ký thiệp sinh nhật, chẳng hạn như "From Emma".
GreetingText(message = "Happy Birthday Sam!", from ="From Emma")
  1. Quan sát bản xem trước này.

ac82fe1c68eb4599.png

Một hàm có khả năng kết hợp có thể mô tả nhiều phần tử trên giao diện người dùng. Tuy nhiên, nếu bạn không cung cấp hướng dẫn về cách sắp xếp chúng, thì Compose có thể sắp xếp các phần tử theo cách bạn không muốn. Ví dụ: mã trước tạo ra hai phần tử văn bản chồng chéo nhau vì chưa có hướng dẫn về cách sắp xếp hai thành phần kết hợp này.

Trong nhiệm vụ tiếp theo, bạn sẽ tìm hiểu cách sắp xếp các thành phần kết hợp trong một hàng và trong một cột.

8. Sắp xếp các phần tử văn bản trong một hàng và cột

Hệ phân cấp giao diện người dùng

Hệ phân cấp giao diện người dùng dựa trên vùng chứa, có nghĩa là một thành phần có thể chứa một hoặc nhiều thành phần khác, theo đó thỉnh thoảng bạn sẽ thấy xuất hiện các thuật ngữ như thành phần mẹ (parent) và con (child). Ngữ cảnh đề cập ở đây là các phần tử mẹ trên giao diện người dùng chứa các phần tử con trên giao diện người dùng. Đến lượt mình, các phần tử con này có thể chứa các phần tử con trên giao diện người dùng. Trong phần này, bạn sẽ tìm hiểu về các thành phần kết hợp Column, RowBox. Những thành phần kết hợp này có thể đóng vai trò là phần tử mẹ trên giao diện người dùng.

9270b7e10f954dcb.png

3 thành phần bố cục tiêu chuẩn, cơ bản trong Compose là các thành phần kết hợp Column, Row, và Box. Bạn có thể tìm hiểu thêm về thành phần kết hợp Box trong lớp học lập trình tiếp theo.

cột hiển thị ba thành phần được sắp xếp theo chiều dọc và hàng hiển thị 3 thành phần được sắp xếp theo chiều ngang

Column, RowBox là các hàm có khả năng kết hợp. Những hàm này sẽ nhận các nội dung có thể kết hợp làm đối số, vì vậy, bạn có thể đặt các thành phần bên trong các thành phần bố cục này. Ví dụ: mỗi thành phần con bên trong một thành phần kết hợp Row có thể đặt ngang hàng với nhau.

// Don't copy.
Row {
    Text("First Column")
    Text("Second Column")
}

Các thành phần văn bản này hiển thị bên cạnh nhau trên màn hình như thể hiện trong hình bên dưới.

Đường viền màu xanh dương chỉ nhằm mục đích minh hoạ và không hiển thị.

6f74a11c03564a61.png

Cú pháp lambda theo sau

Hãy lưu ý rằng trong đoạn mã trước đó, dấu ngoặc nhọn được dùng thay cho dấu ngoặc đơn trong hàm có khả năng kết hợp Row. Hành động này được gọi là Cú pháp Trailing Lambda. Bạn có thể tìm hiểu chi tiết về lambdas và cú pháp lambda ở phần sau trong khoá học này. Bây giờ, hãy làm quen với cú pháp Compose thường dùng.

Kotlin cung cấp một cú pháp đặc biệt để truyền các hàm đến các hàm khác dưới dạng tham số, trong đó tham số cuối cùng sẽ là một hàm.

tham số hàm là tham số cuối cùng

Khi truyền một hàm làm tham số đó, bạn có thể sử dụng cú pháp lambda theo sau. Thay vì đặt nội dung hàm cùng với tên hàm trong dấu ngoặc đơn ({}), bạn sẽ đặt dấu ngoặc đơn cùng với phần nội dung hàm sau tên hàm. Đây là một phương pháp phổ biến và được đề xuất trong Compose, vì vậy, bạn cần phải làm quen với cú pháp viết mã theo cách này.

Ví dụ: tham số cuối cùng trong hàm có khả năng kết hợp Row()content. Đây là một hàm dùng để mô tả các phần tử con trên giao diện người dùng. Giả sử bạn muốn tạo một hàng chứa 3 phần tử văn bản. Mã này sẽ hoạt động tốt, nhưng việc sử dụng tham số có tên cho hàm lambda theo sau là rất cồng kềnh:

Row(
    content = {
        Text("Some text")
        Text("Some more text")
        Text("Last text")
    }
)

Vì tham số content là tham số cuối cùng trong chữ ký hàm (function signature) và bạn truyền giá trị của tham số đó dưới dạng một biểu thức lambda (hiện tại, bạn không cần biết lambda là gì, chỉ cần làm quen với cú pháp), bạn có thể xoá tham số content và các dấu ngoặc đơn như sau:

Row {
    Text("Some text")
    Text("Some more text")
    Text("Last text")
}

Sắp xếp các thành phần văn bản trong một hàng

Trong nhiệm vụ này, bạn sẽ sắp xếp các thành phần văn bản trong ứng dụng thành một hàng để tránh chồng chéo.

  1. Trong tệp MainActivity.kt, hãy di chuyển đến hàm GreetingText().
  2. Thêm thành phần kết hợp Row xung quanh các phần tử văn bản này để hiện 1 hàng gồm 2 phần tử văn bản. Chọn 2 thành phần kết hợp Text, nhấp vào bóng đèn. Chọn Surround with widget (Bao quanh bằng tiện ích) > Surround with Row (Bao quanh bằng hàng).

bb8e10def9aa7b7e.png

ca2ff1086fb0802c.png

Bây giờ, hàm này sẽ có dạng như đoạn mã sau:

@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
    Row {
        Text(
            text = message,
            fontSize = 100.sp,
            lineHeight = 116.sp,
        )
        Text(
            text = from,
            fontSize = 36.sp
        )
    }
}
  1. Android Studio sẽ tự động nhập hàm Row cho bạn. Cuộn lên trên cùng và để ý phần nhập. Bạn phải thêm import androidx.compose.foundation.layout.Row.
  2. Quan sát bản xem trước đã cập nhật trong ngăn Design (Thiết kế). Tạm thời thay đổi kích thước phông chữ cho lời chúc sinh nhật thành 30.sp.

Lời chúc mừng sinh nhật và chữ ký sẽ hiển thị cạnh nhau trên một hàng.

Bản xem trước bây giờ đã đẹp hơn rất nhiều vì các thành phần không còn chồng chéo lẫn nhau. Tuy nhiên, giao diện này vẫn chưa đáp ứng yêu cầu của bạn vì không có đủ không gian cho phần chữ ký. Trong nhiệm vụ tiếp theo, bạn sẽ sắp xếp các thành phần văn bản trong một cột để xử lý vấn đề này.

Sắp xếp các thành phần văn bản trong một cột

Trong việc này, bạn cần thay đổi hàm GreetingText() để sắp xếp các thành phần văn bản trong một cột. Bản xem trước sẽ có dạng như ảnh chụp màn hình sau:

785f6c6e087b03b.png

Bây giờ, bạn đã thử tự làm việc này, vui lòng kiểm tra mã của bạn với đoạn mã giải pháp trong đoạn mã này:

@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
    Column {
        Text(
            text = message,
            fontSize = 100.sp,
            lineHeight = 116.sp
        )
        Text(
            text = from,
            fontSize = 36.sp
        )
    }
}

Hãy lưu ý về gói được tự động nhập bởi Android Studio:

import androidx.compose.foundation.layout.Column

Hãy nhớ rằng bạn cần truyền tham số sửa đổi đến các phần tử con trong thành phần kết hợp. Điều đó có nghĩa là bạn cần truyền tham số sửa đổi tới thành phần kết hợp Column.

@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
    Column(modifier = modifier) {
        Text(
            text = message,
            fontSize = 100.sp,
            lineHeight = 116.sp
        )
        Text(
            text = from,
            fontSize = 36.sp
        )
    }
}

9. Thêm lời chào vào ứng dụng

Khi đã hài lòng với bản xem trước, giờ đã đến lúc để thêm thành phần kết hợp vào ứng dụng trên thiết bị hoặc trình mô phỏng.

  1. Trong tệp MainActivity.kt, chuyển đến hàm onCreate().
  2. Gọi hàm GreetingText() trong khối lệnh Surface.
  3. Truyền lời chúc mừng sinh nhật và chữ ký của bạn vào hàm GreetingText().

Hàm onCreate() hoàn chỉnh sẽ có dạng như đoạn mã sau:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            HappyBirthdayTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    GreetingText(message = "Happy Birthday Sam!", from = "From Emma")
                }
            }
        }
    }
}
  1. Tạo bản dựng và chạy ứng dụng trên trình mô phỏng.

433859d648d9b26.png

Căn chỉnh lời chào vào chính giữa

  1. Để căn chỉnh lời chào ở giữa màn hình, hãy thêm một tham số có tên là verticalArrangement, thiết lập tham số này thành Arrangement.Center. Bạn sẽ tìm hiểu thêm về verticalArrangement trong một lớp học lập trình sau này.
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
    Column(
        verticalArrangement = Arrangement.Center,
        modifier = modifier
    ) {
        // ...
    }
}
  1. Thêm khoảng đệm 8.dp xung quanh cột. Bạn nên sử dụng giá trị khoảng đệm theo gia số 4.dp.
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
    Column(
        verticalArrangement = Arrangement.Center,
        modifier = modifier.padding(8.dp)
    ) {
        // ...
    }
}
  1. Để làm đẹp ứng dụng của bạn, hãy căn chỉnh văn bản lời chào đó vào giữa bằng textAlign.
Text(
    text = message,
    fontSize = 100.sp,
    lineHeight = 116.sp,
    textAlign = TextAlign.Center
)

ac614110dd73da93.png

Trong ảnh chụp màn hình ở trên, chỉ lời chào được căn giữa do tham số textAlign. Chữ ký Người gửi: Emma có căn chỉnh mặc định ở bên trái.

  1. Thêm khoảng đệm vào chữ ký và căn chỉnh sang phải.
Text(
    text = from,
    fontSize = 36.sp,
    modifier = Modifier
        .padding(16.dp)
        .align(alignment = Alignment.End)
)

4c8c1e27bc2f6869.png

Áp dụng phương pháp hay

Bạn nên truyền (các) thuộc tính đối tượng sửa đổi cùng với đối tượng sửa đổi đó qua thành phần kết hợp mẹ. Cập nhật tham số đối tượng sửa đổi trong GreetingText() như sau:

onCreate()

Surface(
    //...
) {
    GreetingText(
        message = "Happy Birthday Sam!",
        from = "From Emma",
        modifier = Modifier.padding(8.dp)
    )
}

GreetingText()

@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
    Column(
        verticalArrangement = Arrangement.Center,
        modifier = modifier
    ) {
        // ...
    }
}

Tạo bản dựng và chạy ứng dụng của bạn trên trình mô phỏng để xem kết quả cuối cùng.

74dd02e4f7fa1780.png

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

MainActivity.kt hoàn chỉnh:

package com.example.happybirthday

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.happybirthday.ui.theme.HappyBirthdayTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            HappyBirthdayTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    GreetingText(
                        message = "Happy Birthday Sam!",
                        from = "From Emma",
                        modifier = Modifier.padding(8.dp)
                    )
                }
            }
        }
    }
}

@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
    Column(
        verticalArrangement = Arrangement.Center,
        modifier = modifier
    ) {
        Text(
            text = message,
            fontSize = 100.sp,
            lineHeight = 116.sp,
            textAlign = TextAlign.Center
        )
        Text(
            text = from,
            fontSize = 36.sp,
            modifier = Modifier
                .padding(16.dp)
                .align(alignment = Alignment.End)
        )
    }
}

@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
    HappyBirthdayTheme {
        GreetingText(message = "Happy Birthday Sam!", from = "From Emma")
    }
}

11. Kết luận

Bạn đã tạo ứng dụng Chúc mừng sinh nhật.

Trong lớp học lập trình tiếp theo, bạn sẽ thêm hình ảnh vào ứng dụng và thay đổi cách căn chỉnh để hiển thị các thành phần văn bản đẹp hơn.

Tóm tắt

  • Jetpack Compose là một bộ công cụ hiện đại giúp xây dựng giao diện người dùng Android. Jetpack Compose giúp đơn giản hóa và tăng tốc quá trình phát triển giao diện người dùng trên Android nhờ dùng ít mã hơn, các công cụ mạnh mẽ và API Kotlin trực quan.
  • Giao diện người dùng (UI) của một ứng dụng là những gì bạn thấy trên màn hình: văn bản, hình ảnh, nút lệnh và nhiều loại thành phần khác.
  • Các hàm có khả năng kết hợp là thành phần xây dựng cơ bản trong Compose. Hàm có khả năng kết hợp là một hàm mô tả một số thành phần trên giao diện người dùng.
  • Hàm có khả năng kết hợp được chú thích bằng chú thích @Composable; chú thích này sẽ thông báo cho trình biên dịch Compose biết rằng hàm này sẽ giúp chuyển đổi dữ liệu thành giao diện người dùng.
  • Ba thành phần bố cục chuẩn cơ bản trong Compose là Column, Row,Box. Đây là các hàm có khả năng kết hợp và nhận tham số là các nội dung có thể kết hợp. Vì vậy, bạn có thể đặt các thành phần bên trong những hàm này. Ví dụ: mỗi thành phần con trong một Row sẽ được xếp cạnh nhau theo chiều ngang.

Tìm hiểu thêm