Trang này mô tả cách xử lý kích thước và cung cấp giải pháp linh hoạt và có khả năng thích ứng bố cục với tính năng Glance, sử dụng các thành phần Glance hiện có.
Sử dụng Box
, Column
và Row
Glance có 3 bố cục thành phần kết hợp chính:
Box
: Đặt các phần tử lên nhau. Thông tin này sẽ dịch sangRelativeLayout
.Column
: Đặt các phần tử sau nhau theo trục tung. Dịch thànhLinearLayout
có hướng dọc.Row
: Đặt các phần tử sau nhau theo trục hoành. Dịch thànhLinearLayout
theo hướng ngang.
Tính năng Glance hỗ trợ các đối tượng Scaffold
. Đặt Column
, Row
và
Các thành phần kết hợp Box
trong một đối tượng Scaffold
nhất định.
Mỗi thành phần kết hợp này cho phép bạn xác định cách căn chỉnh dọc và ngang của nội dung và giới hạn chiều rộng, chiều cao, trọng lượng hoặc khoảng đệm sử dụng đối tượng sửa đổi. Ngoài ra, mỗi thành phần con có thể xác định đối tượng sửa đổi để thay đổi không gian và vị trí bên trong thành phần mẹ.
Ví dụ sau đây cho bạn biết cách tạo Row
phân phối đồng đều
các phần tử con theo chiều ngang, như trong Hình 1:
Row(modifier = GlanceModifier.fillMaxWidth().padding(16.dp)) { val modifier = GlanceModifier.defaultWeight() Text("first", modifier) Text("second", modifier) Text("third", modifier) }
Row
lấp đầy chiều rộng tối đa hiện có và vì mỗi phần tử con có cùng một chiều rộng
trọng số, chúng sẽ chia sẻ đều không gian có sẵn. Bạn có thể xác định các trọng số khác nhau,
kích thước, khoảng đệm hoặc căn chỉnh để điều chỉnh bố cục theo nhu cầu của bạn.
Sử dụng bố cục có thể cuộn
Một cách khác để cung cấp nội dung thích ứng là tạo nội dung có thể cuộn. Đây là
thành phần kết hợp LazyColumn
. Thành phần kết hợp này cho phép bạn xác định một tập hợp
mục được hiển thị bên trong một vùng chứa có thể cuộn trong tiện ích ứng dụng.
Các đoạn mã sau đây cho biết các cách khác nhau để xác định các mục bên trong
LazyColumn
.
Bạn có thể cung cấp số lượng mục:
// Remember to import Glance Composables // import androidx.glance.appwidget.layout.LazyColumn LazyColumn { items(10) { index: Int -> Text( text = "Item $index", modifier = GlanceModifier.fillMaxWidth() ) } }
Cung cấp từng mục:
LazyColumn { item { Text("First Item") } item { Text("Second Item") } }
Cung cấp một danh sách hoặc mảng các mặt hàng:
LazyColumn { items(peopleNameList) { name -> Text(name) } }
Bạn cũng có thể sử dụng kết hợp các ví dụ trước đó:
LazyColumn { item { Text("Names:") } items(peopleNameList) { name -> Text(name) } // or in case you need the index: itemsIndexed(peopleNameList) { index, person -> Text("$person at index $index") } }
Xin lưu ý rằng đoạn mã trước đó không chỉ định itemId
. Chỉ định phương diện
itemId
giúp cải thiện hiệu suất và duy trì thao tác cuộn
vị trí thông qua danh sách và các bản cập nhật appWidget
từ Android 12 trở đi (đối với
ví dụ: khi thêm hoặc xoá mục khỏi danh sách). Ví dụ sau đây
cho biết cách chỉ định một itemId
:
items(items = peopleList, key = { person -> person.id }) { person -> Text(person.name) }
Định nghĩa SizeMode
Kích thước của AppWidget
có thể khác nhau tuỳ thuộc vào thiết bị, lựa chọn của người dùng hoặc trình chạy,
nên điều quan trọng là cung cấp bố cục linh hoạt như được mô tả trong phần Cung cấp
bố cục tiện ích linh hoạt. Glance đơn giản hoá điều này bằng SizeMode
và giá trị LocalSize
. Các phần sau đây mô tả 3
chế độ.
SizeMode.Single
SizeMode.Single
là chế độ mặc định. Nó cho biết rằng chỉ có một loại
nội dung được cung cấp; tức là ngay cả khi kích thước của AppWidget
thay đổi,
kích thước nội dung không thay đổi.
class MyAppWidget : GlanceAppWidget() { override val sizeMode = SizeMode.Single override suspend fun provideGlance(context: Context, id: GlanceId) { // ... provideContent { MyContent() } } @Composable private fun MyContent() { // Size will be the minimum size or resizable // size defined in the App Widget metadata val size = LocalSize.current // ... } }
Khi sử dụng chế độ này, hãy đảm bảo rằng:
- Giá trị siêu dữ liệu kích thước tối thiểu và tối đa được xác định đúng cách dựa trên về kích thước nội dung.
- Nội dung đủ linh hoạt trong phạm vi kích thước dự kiến.
Nói chung, bạn nên sử dụng chế độ này khi:
a) AppWidget
có kích thước cố định, hoặc
b) nội dung không thay đổi khi được đổi kích thước.
SizeMode.Responsive
Chế độ này tương đương với việc cung cấp bố cục thích ứng, cho phép
GlanceAppWidget
để xác định một tập hợp bố cục thích ứng được giới hạn bởi
kích thước. Đối với mỗi kích thước đã xác định, nội dung sẽ được tạo và ánh xạ với
khi AppWidget
được tạo hoặc cập nhật. Sau đó, hệ thống chọn
phù hợp nhất dựa trên kích thước có sẵn.
Ví dụ: trong đích đến AppWidget
, bạn có thể xác định 3 kích thước và
nội dung:
class MyAppWidget : GlanceAppWidget() { companion object { private val SMALL_SQUARE = DpSize(100.dp, 100.dp) private val HORIZONTAL_RECTANGLE = DpSize(250.dp, 100.dp) private val BIG_SQUARE = DpSize(250.dp, 250.dp) } override val sizeMode = SizeMode.Responsive( setOf( SMALL_SQUARE, HORIZONTAL_RECTANGLE, BIG_SQUARE ) ) override suspend fun provideGlance(context: Context, id: GlanceId) { // ... provideContent { MyContent() } } @Composable private fun MyContent() { // Size will be one of the sizes defined above. val size = LocalSize.current Column { if (size.height >= BIG_SQUARE.height) { Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp)) } Row(horizontalAlignment = Alignment.CenterHorizontally) { Button() Button() if (size.width >= HORIZONTAL_RECTANGLE.width) { Button("School") } } if (size.height >= BIG_SQUARE.height) { Text(text = "provided by X") } } } }
Trong ví dụ trước, phương thức provideContent
được gọi 3 lần và
được ánh xạ theo kích thước xác định.
- Trong lệnh gọi đầu tiên, kích thước được đánh giá là
100x100
. Nội dung không bao gồm nút bổ sung, cũng như văn bản ở trên cùng và dưới cùng. - Trong lệnh gọi thứ hai, kích thước được đánh giá là
250x100
. Nội dung này bao gồm nút bổ sung, nhưng không phải là văn bản trên cùng và dưới cùng. - Trong lệnh gọi thứ ba, kích thước được đánh giá là
250x250
. Nội dung này bao gồm nút bổ sung và cả hai văn bản.
SizeMode.Responsive
là sự kết hợp của hai chế độ còn lại, cho phép bạn
xác định nội dung thích ứng trong giới hạn được xác định trước. Nhìn chung, chế độ này
hoạt động hiệu quả hơn và cho phép chuyển đổi suôn sẻ hơn khi AppWidget
đổi kích thước.
Bảng sau đây trình bày giá trị của kích thước, tuỳ thuộc vào SizeMode
và
kích thước có sẵn AppWidget
:
Kích thước hiện có | 105 x 110 | 203 x 112 | 72 x 72 | 203 x 150 |
---|---|---|---|---|
SizeMode.Single |
110 x 110 | 110 x 110 | 110 x 110 | 110 x 110 |
SizeMode.Exact |
105 x 110 | 203 x 112 | 72 x 72 | 203 x 150 |
SizeMode.Responsive |
80 x 100 | 80 x 100 | 80 x 100 | 150 x 120 |
* Các giá trị chính xác này chỉ nhằm mục đích minh hoạ. |
SizeMode.Exact
SizeMode.Exact
tương đương với việc cung cấp bố cục chính xác,
yêu cầu nội dung GlanceAppWidget
mỗi khi kích thước AppWidget
có sẵn
các thay đổi (ví dụ: khi người dùng đổi kích thước AppWidget
trong màn hình chính).
Ví dụ: trong tiện ích đích, bạn có thể thêm một nút bổ sung nếu chiều rộng có sẵn lớn hơn một giá trị nhất định.
class MyAppWidget : GlanceAppWidget() { override val sizeMode = SizeMode.Exact override suspend fun provideGlance(context: Context, id: GlanceId) { // ... provideContent { MyContent() } } @Composable private fun MyContent() { // Size will be the size of the AppWidget val size = LocalSize.current Column { Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp)) Row(horizontalAlignment = Alignment.CenterHorizontally) { Button() Button() if (size.width > 250.dp) { Button("School") } } } } }
Chế độ này linh hoạt hơn các chế độ khác, nhưng đi kèm với một vài cảnh báo:
AppWidget
phải được tạo lại hoàn toàn mỗi khi kích thước thay đổi. Chiến dịch này có thể dẫn đến các vấn đề về hiệu suất và giao diện người dùng thay đổi khi nội dung phức tạp.- Kích thước có sẵn có thể khác nhau tuỳ thuộc vào cách triển khai trình chạy. Ví dụ: nếu trình chạy không cung cấp danh sách kích thước, thì giá trị tối thiểu kích thước có thể sử dụng.
- Trên các thiết bị chạy Android 12 trở xuống, logic tính kích thước có thể không hoạt động ngoại lệ.
Nói chung, bạn nên sử dụng chế độ này nếu không thể sử dụng SizeMode.Responsive
(nghĩa là không thể thực hiện một tập hợp nhỏ các bố cục thích ứng).
Truy cập vào tài nguyên
Sử dụng LocalContext.current
để truy cập vào bất kỳ tài nguyên Android nào, như minh hoạ trong
ví dụ sau:
LocalContext.current.getString(R.string.glance_title)
Bạn nên cung cấp trực tiếp mã nhận dạng tài nguyên để giảm kích thước của phần tử cuối cùng
đối tượng RemoteViews
và để bật các tài nguyên động, chẳng hạn như động
màu.
Các thành phần kết hợp và phương thức sẽ chấp nhận tài nguyên bằng cách sử dụng một "nhà cung cấp", chẳng hạn như
ImageProvider
hoặc sử dụng phương thức nạp chồng như
GlanceModifier.background(R.color.blue)
Ví dụ:
Column( modifier = GlanceModifier.background(R.color.default_widget_background) ) { /**...*/ } Image( provider = ImageProvider(R.drawable.ic_logo), contentDescription = "My image", )
Xử lý văn bản
Glance 1.1.0 bao gồm một API để thiết lập kiểu văn bản của bạn. Đặt kiểu văn bản bằng
Các thuộc tính fontSize
, fontWeight
hoặc fontFamily
của lớp TextStyle.
fontFamily
hỗ trợ tất cả phông chữ hệ thống, như trong ví dụ sau, nhưng
phông chữ tùy chỉnh trong ứng dụng không được hỗ trợ:
Text(
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
fontFamily = FontFamily.Monospace
),
text = "Example Text"
)
Thêm nút phức hợp
Nút phức hợp đã được giới thiệu trong Android 12. Tính năng Glance hỗ trợ thao tác quay lại khả năng tương thích cho các loại nút phức hợp sau đây:
Mỗi nút phức hợp này hiển thị một khung hiển thị có thể nhấp, đại diện cho "đã chọn" trạng thái.
var isApplesChecked by remember { mutableStateOf(false) } var isEnabledSwitched by remember { mutableStateOf(false) } var isRadioChecked by remember { mutableStateOf(0) } CheckBox( checked = isApplesChecked, onCheckedChange = { isApplesChecked = !isApplesChecked }, text = "Apples" ) Switch( checked = isEnabledSwitched, onCheckedChange = { isEnabledSwitched = !isEnabledSwitched }, text = "Enabled" ) RadioButton( checked = isRadioChecked == 1, onClick = { isRadioChecked = 1 }, text = "Checked" )
Khi trạng thái thay đổi, hàm lambda đã cung cấp sẽ được kích hoạt. Bạn có thể lưu trữ kiểm tra trạng thái, như trong ví dụ sau:
class MyAppWidget : GlanceAppWidget() { override suspend fun provideGlance(context: Context, id: GlanceId) { val myRepository = MyRepository.getInstance() provideContent { val scope = rememberCoroutineScope() val saveApple: (Boolean) -> Unit = { scope.launch { myRepository.saveApple(it) } } MyContent(saveApple) } } @Composable private fun MyContent(saveApple: (Boolean) -> Unit) { var isAppleChecked by remember { mutableStateOf(false) } Button( text = "Save", onClick = { saveApple(isAppleChecked) } ) } }
Bạn cũng có thể cung cấp thuộc tính colors
cho CheckBox
, Switch
và
RadioButton
để tuỳ chỉnh màu:
CheckBox( // ... colors = CheckboxDefaults.colors( checkedColor = ColorProvider(day = colorAccentDay, night = colorAccentNight), uncheckedColor = ColorProvider(day = Color.DarkGray, night = Color.LightGray) ), checked = isChecked, onCheckedChange = { isChecked = !isChecked } ) Switch( // ... colors = SwitchDefaults.colors( checkedThumbColor = ColorProvider(day = Color.Red, night = Color.Cyan), uncheckedThumbColor = ColorProvider(day = Color.Green, night = Color.Magenta), checkedTrackColor = ColorProvider(day = Color.Blue, night = Color.Yellow), uncheckedTrackColor = ColorProvider(day = Color.Magenta, night = Color.Green) ), checked = isChecked, onCheckedChange = { isChecked = !isChecked }, text = "Enabled" ) RadioButton( // ... colors = RadioButtonDefaults.colors( checkedColor = ColorProvider(day = Color.Cyan, night = Color.Yellow), uncheckedColor = ColorProvider(day = Color.Red, night = Color.Blue) ), )
Thành phần bổ sung
Glance 1.1.0 bao gồm việc phát hành các thành phần bổ sung, như được mô tả trong bảng sau:
Tên | Hình ảnh | Đường liên kết đến tài liệu tham khảo | Ghi chú khác |
---|---|---|---|
Nút được tô màu nền | Thành phần | ||
Nút có đường viền | Thành phần | ||
Nút biểu tượng | Thành phần | Chính / phụ / Chỉ biểu tượng | |
Thanh tiêu đề | Thành phần | ||
Scaffold | Scaffold và Title bar nằm trong cùng một bản minh hoạ. |
Để biết thêm thông tin về các chi tiết thiết kế cụ thể, hãy xem thiết kế thành phần trong thiết kế trên Figma.