Kiến thức cơ bản về kiểu

Có 3 cách để bạn có thể áp dụng Kiểu trong ứng dụng:

  1. Sử dụng trực tiếp trên các thành phần hiện có có tham số Style.
  2. Áp dụng kiểu bằng Modifier.styleable trên các thành phần kết hợp bố cục không chấp nhận tham số Style.
  3. Trong hệ thống thiết kế tuỳ chỉnh của riêng bạn, hãy sử dụng Modifier.styleable{} và hiển thị một tham số kiểu trên các thành phần của riêng bạn.

Các thuộc tính có sẵn trên Kiểu

Kiểu hỗ trợ nhiều thuộc tính giống như đối tượng sửa đổi; tuy nhiên, không phải mọi thứ là đối tượng sửa đổi đều có thể được sao chép bằng Kiểu. Bạn vẫn cần các đối tượng sửa đổi cho một số hành vi, chẳng hạn như tương tác, vẽ tuỳ chỉnh hoặc xếp chồng các thuộc tính.

Nhóm Thuộc tính Được trẻ em thừa hưởng
Bố cục và kích thước
Khoảng đệm contentPadding (bên trong) và externalPadding (bên ngoài). Có các biến thể theo hướng, chiều ngang, chiều dọc và tất cả các hướng. Không
Kích thước fillWidth/Height/Size()width, heightsize (hỗ trợ các phân số Dp, DpSize hoặc Float). Không
Khẳng định vị thế left/top/right/bottom độ lệch. Không
Giao diện trực quan
Đổ đầy backgroundforeground (hỗ trợ Color hoặc Brush). Không
Đường viền borderWidth, borderColorborderBrush. Không
Hình dạng shape Không, nhưng được dùng cùng với các thuộc tính khác. clipborder sử dụng hình dạng đã xác định này.
Bóng dropShadow, innerShadow Không
Phép biến đổi
Chuyển động không gian của lớp đồ hoạ translationX, translationY, scaleX/Y, rotationX/Y/Z Không
Kiểm soát alpha, zIndex (thứ tự xếp chồng) và transformOrigin (điểm xoay) Không
Kiểu chữ
Tạo kiểu textStyle, fontSize, fontWeight, fontStylefontFamily
Màu sắc contentColorcontentBrush. Thuộc tính này cũng được dùng để tạo kiểu cho biểu tượng.
Đoạn lineHeight, letterSpacing, textAlign, textDirection, lineBreakhyphens.
Trang trí textDecoration, textIndentbaselineShift.

Sử dụng Kiểu trực tiếp trên các thành phần bằng tham số Kiểu

Các thành phần hiển thị tham số Style cho phép bạn đặt kiểu cho các thành phần đó:

BaseButton(
    onClick = { },
    style = { }
) {
    BaseText("Click me")
}

Trong hàm lambda kiểu, bạn có thể đặt nhiều thuộc tính, chẳng hạn như externalPadding hoặc background:

BaseButton(
    onClick = { },
    style = { background(Color.Blue) }
) {
    BaseText("Click me")
}

Để xem danh sách đầy đủ các thuộc tính được hỗ trợ, hãy xem Các thuộc tính có sẵn trên Styles.

Áp dụng Kiểu bằng cách sử dụng đối tượng sửa đổi cho các thành phần không có tham số hiện có

Đối với những thành phần không có tham số kiểu tích hợp, bạn vẫn có thể áp dụng các kiểu bằng đối tượng sửa đổi styleable. Phương pháp này cũng hữu ích khi bạn phát triển các thành phần tuỳ chỉnh của riêng mình.

Row(
    modifier = Modifier.styleable { }
) {
    BaseText("Content")
}

Tương tự như tham số style, bạn có thể thêm các thuộc tính như background hoặc padding vào bên trong lambda.

Row(
    modifier = Modifier.styleable {
        background(Color.Blue)
    }
) {
    BaseText("Content")
}

Nhiều đối tượng sửa đổi Modifier.styleable được liên kết có tính chất cộng thêm với các thuộc tính không được kế thừa trên thành phần kết hợp được áp dụng, hoạt động tương tự như nhiều đối tượng sửa đổi xác định cùng một thuộc tính. Đối với các thuộc tính được kế thừa, các thuộc tính này sẽ bị ghi đè và đối tượng sửa đổi styleable cuối cùng trong chuỗi sẽ đặt các giá trị.

Khi sử dụng Modifier.styleable, bạn cũng có thể muốn tạo và cung cấp một StyleState để dùng với đối tượng sửa đổi nhằm áp dụng kiểu dựa trên trạng thái. Để biết thêm thông tin chi tiết, hãy xem bài viết Trạng thái và ảnh động bằng Kiểu.

Xác định một Kiểu độc lập

Bạn có thể xác định một Kiểu độc lập cho mục đích sử dụng lại:

val style = Style { background(Color.Blue) }

Sau đó, bạn có thể truyền kiểu đã xác định đó vào tham số kiểu của thành phần kết hợp hoặc bằng Modifier.styleable. Khi sử dụng Modifier.styleable, bạn cũng cần tạo một đối tượng StyleState. StyleState được đề cập chi tiết trong tài liệu Trạng thái và ảnh động bằng Kiểu.

Ví dụ sau đây cho thấy cách bạn có thể áp dụng một Kiểu trực tiếp thông qua các tham số tích hợp của thành phần hoặc thông qua Modifier.styleable:

val style = Style { background(Color.Blue) }

// built in parameter
BaseButton(onClick = { }, style = style) {
    BaseText("Button")
}

// modifier styleable
val styleState = remember { MutableStyleState(null) }
Column(
    Modifier.styleable(styleState, style)
) {
    BaseText("Column content")
}

Bạn cũng có thể truyền Style đó vào nhiều thành phần:

val style = Style { background(Color.Blue) }

// built in parameter
BaseButton(onClick = { }, style = style) {
    BaseText("Button")
}
BaseText("Different text that uses the same style parameter", style = style)

// modifier styleable
val columnStyleState = remember { MutableStyleState(null) }
Column(
    Modifier.styleable(columnStyleState, style)
) {
    BaseText("Column")
}
val rowStyleState = remember { MutableStyleState(null) }
Row(
    Modifier.styleable(rowStyleState, style)
) {
    BaseText("Row")
}

Thêm nhiều thuộc tính Kiểu

Bạn có thể thêm nhiều thuộc tính Kiểu bằng cách đặt các thuộc tính khác nhau trên mỗi dòng:

BaseButton(
    onClick = { },
    style = {
        background(Color.Blue)
        contentPaddingStart(16.dp)
    }
) {
    BaseText("Button")
}

Các thuộc tính trong Kiểu không được cộng dồn, không giống như kiểu dựa trên đối tượng sửa đổi. Kiểu lấy giá trị được đặt cuối cùng trong danh sách thuộc tính trong một khối kiểu. Trong ví dụ sau, khi bạn đặt nền hai lần, TealColor là nền được áp dụng. Đối với khoảng đệm, contentPaddingTop sẽ ghi đè khoảng đệm trên do contentPadding đặt và không kết hợp các giá trị.

BaseButton(
    style = {
        background(Color.Red)
        // Background of Red is now overridden with TealColor instead
        background(TealColor)
        // All directions of padding are set to 64.dp (top, start, end, bottom)
        contentPadding(64.dp)
        // Top padding is now set to 16.dp, all other paddings remain at 64.dp
        contentPaddingTop(16.dp)
    },
    onClick = {
        //
    }
) {
    BaseText("Click me!")
}

Nút có 2 màu nền được đặt và 2 chế độ ghi đè contentPadding
Hình 1. Nút có 2 màu nền được đặt và 2 chế độ ghi đè contentPadding.

Hợp nhất nhiều đối tượng kiểu

Bạn có thể tạo nhiều đối tượng Kiểu và truyền các đối tượng đó vào tham số kiểu của thành phần kết hợp.

val style1 = Style { background(TealColor) }
val style2 = Style { contentPaddingTop(16.dp) }

BaseButton(
    style = style1 then style2,
    onClick = {

    },
) {
    BaseText("Click me!")
}

Nút có màu nền và contentPaddingTop được đặt
Hình 2. Nút có màu nền và contentPaddingTop được đặt.

Khi nhiều Kiểu chỉ định cùng một thuộc tính, thuộc tính được đặt gần đây nhất sẽ được chọn. Vì các thuộc tính không được cộng thêm trong Styles, nên khoảng đệm cuối cùng được truyền vào sẽ ghi đè contentPaddingHorizontal do contentPadding ban đầu đặt. Ngoài ra, màu nền cuối cùng sẽ ghi đè màu nền do kiểu ban đầu được truyền vào đặt.

val style1 = Style {
    background(Color.Red)
    contentPadding(32.dp)
}

val style2 = Style {
    contentPaddingHorizontal(8.dp)
    background(Color.LightGray)
}

BaseButton(
    style = style1 then style2,
    onClick = {

    },
) {
    BaseText("Click me!")
}

Trong trường hợp này, kiểu áp dụng có nền màu xám nhạt và khoảng đệm 32.dp, ngoại trừ khoảng đệm bên trái và bên phải có giá trị là 8.dp.

Nút có contentPadding bị ghi đè bởi các Kiểu khác nhau
Hình 3. Nút có contentPadding bị ghi đè bởi nhiều Kiểu.

Kế thừa kiểu

Một số thuộc tính kiểu, chẳng hạn như contentColor và các thuộc tính liên quan đến kiểu văn bản, sẽ truyền đến các thành phần kết hợp con. Một kiểu được đặt trên thành phần kết hợp con sẽ ghi đè kiểu gốc được kế thừa cho thành phần con cụ thể đó.

Truyền kiểu bằng các tham số Style, styleable và direct
Hình 4. Lan truyền kiểu bằng Style, styleable và các tham số trực tiếp.
Mức độ ưu tiên Phương thức Hiệu ứng
1 (Cao nhất) Đối số trực tiếp trên một thành phần kết hợp Ghi đè mọi thứ; ví dụ: Text(color = Color.Red)
2 Tham số kiểu Ghi đè kiểu cục bộ Text(style = Style { contentColor(Color.Red)}
3 Chuỗi bổ từ Modifier.styleable{ contentColor(Color.Red) trên chính thành phần đó.
4 (Thấp nhất) Kiểu gốc Đối với các thuộc tính có thể được kế thừa (Kiểu chữ/Màu sắc) được truyền xuống từ thành phần mẹ.

Định kiểu cho phần tử mẹ

Bạn có thể đặt các thuộc tính văn bản (chẳng hạn như contentColor) từ thành phần kết hợp mẹ và các thuộc tính này sẽ truyền đến tất cả thành phần kết hợp Text con.

val styleState = remember { MutableStyleState(null) }
Column(
    modifier = Modifier.styleable(styleState) {
        background(Color.LightGray)
        val blue = Color(0xFF4285F4)
        val purple = Color(0xFFA250EA)
        val colors = listOf(blue, purple)
        contentBrush(Brush.linearGradient(colors))
    },
) {
    BaseText("Children inherit", style = { width(60.dp) })
    BaseText("certain properties")
    BaseText("from their parents")
}

Tính kế thừa thuộc tính của thành phần kết hợp con
Hình 5. Tính kế thừa thuộc tính của các thành phần kết hợp con.

Thành phần con ghi đè các thuộc tính

Bạn cũng có thể đặt kiểu cho một thành phần kết hợp Text cụ thể. Nếu thành phần kết hợp mẹ có kiểu được đặt, thì kiểu được đặt trên thành phần kết hợp con sẽ ghi đè kiểu của thành phần kết hợp mẹ.

val styleState = remember { MutableStyleState(null) }
Column(
    modifier = Modifier.styleable(styleState) {
        background(Color.LightGray)
        val blue = Color(0xFF4285F4)
        val purple = Color(0xFFA250EA)
        val colors = listOf(blue, purple)
        contentBrush(Brush.linearGradient(colors))
    },
) {
    BaseText("Children can ", style = {
        contentBrush(Brush.linearGradient(listOf(Color.Red, Color.Blue)))
    })
    BaseText("override properties")
    BaseText("set by their parents")
}

Các thành phần kết hợp con sẽ ghi đè các thuộc tính mẹ
Hình 6. Các thành phần kết hợp con sẽ ghi đè các thuộc tính của thành phần kết hợp mẹ.

Triển khai các thuộc tính Kiểu tuỳ chỉnh

Bạn có thể tạo các thuộc tính tuỳ chỉnh ánh xạ đến các định nghĩa Kiểu hiện có bằng cách sử dụng các hàm tiện ích trên StyleScope, như minh hoạ trong ví dụ sau:

fun StyleScope.outlinedBackground(color: Color) {
    border(1.dp, color)
    background(color)
}

Áp dụng thuộc tính mới này trong một định nghĩa Kiểu:

val customExtensionStyle = Style {
    outlinedBackground(Color.Blue)
}

Không hỗ trợ việc tạo các thuộc tính mới có thể tạo kiểu. Nếu trường hợp sử dụng của bạn yêu cầu hỗ trợ như vậy, hãy gửi yêu cầu về tính năng.

Đọc các giá trị CompositionLocal

Đây là một mẫu phổ biến để lưu trữ mã thông báo hệ thống thiết kế trong CompositionLocal, nhằm truy cập vào các biến mà không cần truyền chúng làm tham số. Các kiểu có thể truy cập vào CompositionLocal để truy xuất các giá trị trên toàn hệ thống trong một kiểu:

val buttonStyle = Style {
    contentPadding(12.dp)
    shape(RoundedCornerShape(50))
    background(Brush.verticalGradient(LocalCustomColors.currentValue.background))
}