+2

Sử dụng ConstraintLayout trong Jetpack Compose

Giới thiệu

Đến nay, chúng ta có thể đã làm việc với ConstraintLayout trong các dự án Android của mình. Nhưng trong bài đăng này, chúng ta sẽ nói về cách chúng ta có thể sử dụng ConstraintLayout trong Jetpack Compose.

Trong bài đăng này, chúng ta sẽ thảo luận về:

  1. ConstraintLayout là gì?
  2. Làm thế nào chúng ta có thể sử dụng ConstraintLayout trong dự án của mình?

ConstraintLayout là gì?

ConstraintLayout là một ViewGroup sắp xếp các thành phần con của nó dựa trên các ràng buộc tương đối giữa các view khác nhau bên trong nó hoặc chính parent.

ConstraintLayout giúp chúng ta thiết kế giao diện người dùng linh hoạt cho màn hình của mình và giảm sự lồng ghép của các view bằng cách duy trì một cấu trúc phẳng. Điều này cũng cải thiện hiệu suất của bố cục cũng như giảm số lượng view lồng ghép trong đó.

Làm thế nào chúng ta có thể sử dụng ConstraintLayout trong dự án của mình?

Trong dự án này, chúng tôi sẽ xây dựng 1 UI tương tự thế này, Ở đây, chúng ta có một hình ảnh và hai TextView. Chúng ta sẽ sử dụng ConstraintLayout để căn chỉnh tất cả các thành phần này.

Đầu tiên, hãy thiết kế một container sẽ chứa ConstraintLayout và các thành phần con của nó. Ở đây, chúng ta sẽ sử dụng Scaffold cho mục đích này.

Scaffold(
    scaffoldState = scaffoldState,
    bodyContent = {
      
    }
)

Ở đây trong bodyContent, chúng ta sẽ thêm code cho ConstraintLayout của mình.

Một ConstraintLayout trong Compose tương tự như một ConstraintLayout trong Hệ thống Xem Android cổ điển, nhưng ở đây nó là một hàm composable. Chúng ta có thể thiết kế một bố cục đơn giản trong ConstraintLayout như sau:

@Composable fun MyConstraintLayoutView(){
    ConstraintLayout(constraintSet = ConstraintSet {}) {
        Text("Hey Mindorks")
    }
}

Ở đây, ConstraintLayout là container sẽ chứa:

  • ConstraintSet: Bộ ràng buộc sẽ được sử dụng trên các view để căn chỉnh nó với các view khác.

  • Children: Các composable khác sẽ giúp chúng ta thiết kế các view.

Bây giờ, hãy thiết kế SplashView của chúng ta theo thiết kế trên.

Chúng ta sẽ khai báo ConstraintLayout và chúng ta sẽ khai báo ConstraintSet bên trong, trong đó chúng ta sẽ khai báo ràng buộc như sau:

Scaffold(
    scaffoldState = scaffoldState,
    bodyContent = {
        ConstraintLayout(ConstraintSet {

            val surface = tag(SURFACE_TAG)
            val textFrom = tag(TEXT_FROM_TAG)
            val textCompany = tag(TEXT_COMPANY_TAG)
            val imageLogo = tag(IMAGE_LOGO_TAG)
        }
        )
    }
)

Ở đây, tag() có các giá trị không đổi,

private const val SURFACE_TAG = "surface"
private const val TEXT_FROM_TAG = "textFrom"
private const val TEXT_COMPANY_TAG = "textCompany"
private const val IMAGE_LOGO_TAG = "imageLogo"

Bây giờ, chúng ta sẽ thêm các biến bằng cách sử dụng một thẻ thuộc loại,

ConstrainedLayoutReference

Điều này giúp chúng ta tham chiếu đến các tiện ích mà chúng ta sẽ tạo ra, tương ứng với các thành phần con của ConstraintLayout với một thẻ cụ thể, có thể được sử dụng để định nghĩa ràng buộc được áp đặt lên các thành phần con đó.

tagcó thể được coi là findViewById.

Bây giờ, chúng ta sẽ đặt ràng buộc cho 4 tham chiếu bố cục này.

Ở đây, surface giống như nền mà chúng ta muốn căn chỉnh với phía trên, dưới, bên phải và bên trái của parent. Vì vậy, để thêm ràng buộc cho nó, chúng ta sẽ sử dụng:

surface.apply {
    left constrainTo parent.left
    top constrainTo parent.top
    right constrainTo parent.right
    bottom constrainTo parent.bottom
}

Ở đây, chúng ta đã ràng buộc surface với trái, phải, dưới và trên của parent.

Ở đây, left (trái) là hướng của các thành phần con và chúng ta sử dụng constrainTo để đặt ràng buộc cần thiết cho nó bằng cách ánh xạ đến view khác.

Còn lại ở đây theo hướng children và chúng tôi sử dụng constrainTo để đặt các ràng buộc cần thiết cho nó bằng cách ánh xạ sang chế độ xem khác.

Ở đây, từ hình ảnh, hãy coi hình vuông là parent và hình tròn là surface. Sau đó, phía bên trái của hình tròn được ràng buộc với bên trái của parent và tương tự cho tất cả các bên khác.

 left constrainTo parent.left 

cũng có nghĩa khi chúng ta ràng buộc bên trái của view với bên trái của parent.

Tương tự, chúng ta muốn imageLogo được ràng buộc với trung tâm và chiều rộng và chiều cao là wrap. Đối với điều đó, chúng ta sẽ sử dụng:

imageLogo.apply {
    left constrainTo parent.left
    top constrainTo parent.top
    right constrainTo parent.right
    bottom constrainTo parent.bottom
    width to wrap
    height to wrap
}

Ở đây, chúng ta đã ràng buộc imageLogo với trái, phải, dưới và trên của parent. Chúng ta cũng thấy rằng chúng ta đã đặt chiều rộng và chiều cao là wrap.

Bây giờ, đối với textCompany, chúng ta muốn nó được ràng buộc ở dưới cùng của màn hình và textFrom được ràng buộc với textCompany.

textCompany.apply {
    bottom constrainTo parent.bottom
    right constrainTo parent.right
    left constrainTo parent.left
}
textFrom.apply {
    bottom constrainTo textCompany.top
    right constrainTo textCompany.right
    left constrainTo textCompany.left
}

Ở đây, textCompany được ràng buộc với phía dưới, bên phải và bên trái của parent và textFrom được ràng buộc với phía trên, bên phải và bên trái của textCompany.

Bây giờ, vì chúng ta đã thêm ràng buộc, mã nguồn hoàn chỉnh sẽ trông như sau:

Scaffold(
    scaffoldState = scaffoldState,
    bodyContent = {
        ConstraintLayout(ConstraintSet {

            val surface = tag(SURFACE_TAG)
            val textFrom = tag(TEXT_FROM_TAG)
            val textCompany = tag(TEXT_COMPANY_TAG)
            val imageLogo = tag(IMAGE_LOGO_TAG)

            surface.apply {
                left constrainTo parent.left
                top constrainTo parent.top
                right constrainTo parent.right
                bottom constrainTo parent.bottom
            }
            imageLogo.apply {
                left constrainTo parent.left
                top constrainTo parent.top
                right constrainTo parent.right
                bottom constrainTo parent.bottom
                width to wrap
                height to wrap
            }
            textCompany.apply {
                bottom constrainTo parent.bottom
                right constrainTo parent.right
                left constrainTo parent.left
            }
            textFrom.apply {
                bottom constrainTo textCompany.top
                right constrainTo textCompany.right
                left constrainTo textCompany.left
            }

        }) {
          //our views
        }
    })

Hãy bắt đầu thiết kế các view và thêm các ràng buộc này vào.

Chúng ta sẽ cần 4 view, một cho surface, một ImageView và hai TextView.

Vì vậy, hãy bắt đầu bằng cách thiết kế một view cho surface. Chúng ta sẽ tạo một hộp container như sau:

Box(
    modifier = Modifier.fillMaxSize() +
            Modifier.drawBackground(colorLightGreen()) +
            Modifier.tag(SURFACE_TAG)
)

Ở đây, chúng ta đã thêm một modifier fill cho maxWidthmaxHeight có sẵn. Điều này sẽ thêm một nền màu xanh lá cây bằng cách sử dụng drawBackground(). Cuối cùng, để thực hiện ràng buộc chúng ta đã thêm ở trên, chúng ta sử dụng Modifier.tag() với SURFACE_TAG chúng ta đã định nghĩa ở trên.

Bằng cách sử dụng tag(), chúng ta sẽ thực hiện ràng buộc cho Box mà chúng ta đã thêm ở trên. Điều này sẽ thực hiện một nền màu xanh lá cây với chiều rộng và chiều cao đầy đủ.

Bây giờ, cho các view khác, chúng ta sẽ thêm các constraints bằng cách sử dụng Modifier.tag() và các view sẽ được ràng buộc vào vị trí đó. Để thiết kế phần còn lại của các view, chúng ta sẽ viết sử dụng:

Text(
    text = "from",
    modifier = Modifier.tag(TEXT_FROM_TAG) + Modifier.padding(bottom = _8dp),
    color = Color.DarkGray
)
Text(
    text = "FACEBOOK",
    style = TextStyle(
        fontSize = _20sp,
        fontFamily = FontFamily.SansSerif,
        fontStyle = FontStyle.Normal
    ),
    modifier = Modifier.tag(TEXT_COMPANY_TAG) + Modifier.padding(bottom = _16dp),
    color = colorGreen()
)

ImageLoader.load(
    imageUrl = R.drawable.ic_whatsapp,
    modifier = Modifier.tag(IMAGE_LOGO_TAG)
) {}

Ở đây, chúng ta đã thêm các thẻ cho cả ba view và chúng bây giờ đã thực hiện các ràng buộc mà chúng ta đã định nghĩa trước đó. ImageLoader.Load() là một hàm composable giúp chúng ta tải hình ảnh và mã nguồn trông như sau:

@Composable
fun load(@DrawableRes imageUrl: Int, modifier: Modifier, onClick: (Boolean) -> Unit) {

    val vectorAsset = loadVectorResource(imageUrl)
    vectorAsset.resource.resource?.let {
        Clickable(onClick = {
            onClick(true)
        }) {
            Image(
                asset = it,
                modifier = modifier,
                contentScale = ContentScale.Fit

            )
        }
    }
}

Bây giờ, nếu chúng ta chạy ứng dụng cài đặt chế độ xem này, chúng ta sẽ nhận được kết quả mong muốn.

Kết luận

Trong Jetpack Compose, chúng tôi vẫn sử dụng ConstraintLayout giống như cách chúng tôi sử dụng nó trong XML bằng cách ràng buộc nó với các chế độ xem và chế độ xem gốc để tạo bố cục.

Nguồn: https://blog.mindorks.com/constraint-layout-in-jetpack-compose/


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí