Halaman ini menjelaskan cara menangani ukuran serta memberikan fleksibilitas dan responsif dengan Glance, menggunakan komponen Glance yang ada.
Gunakan Box
, Column
, dan Row
Glance memiliki tiga tata letak composable utama:
Box
: Menempatkan elemen di atas elemen lain. Diterjemahkan menjadiRelativeLayout
.Column
: Menempatkan elemen-elemen setelah satu sama lain dalam sumbu vertikal. Terjemahan keLinearLayout
dengan orientasi vertikal.Row
: Menempatkan elemen-elemen setelah satu sama lain dalam sumbu horizontal. Terjemahan keLinearLayout
dengan orientasi horizontal.
Glance mendukung objek Scaffold
. Tempatkan Column
, Row
, dan
Composable Box
dalam objek Scaffold
tertentu.
Setiap composable ini memungkinkan Anda menentukan perataan vertikal dan horizontal kontennya dan batasan lebar, tinggi, tebal, atau padding menggunakan pengubah. Selain itu, setiap turunan dapat menentukan pengubahnya untuk mengubah spasi dan penempatan di dalam induk.
Contoh berikut menunjukkan cara membuat Row
yang mendistribusikan secara merata
turunannya secara horizontal, seperti terlihat pada Gambar 1:
Row(modifier = GlanceModifier.fillMaxWidth().padding(16.dp)) { val modifier = GlanceModifier.defaultWeight() Text("first", modifier) Text("second", modifier) Text("third", modifier) }
Row
mengisi lebar maksimum yang tersedia, dan karena setiap turunan memiliki
bobot, mereka akan berbagi ruang yang tersedia secara merata. Anda dapat menentukan bobot yang berbeda,
ukuran, {i>padding<i}, atau {i>alignment<i} untuk menyesuaikan tata letak dengan kebutuhan Anda.
Menggunakan tata letak yang dapat di-scroll
Cara lain untuk menyediakan konten responsif adalah dengan membuatnya dapat di-scroll. Ini adalah
dapat dilakukan dengan composable LazyColumn
. Composable ini memungkinkan Anda menentukan kumpulan
item yang akan ditampilkan dalam container yang dapat di-scroll di widget aplikasi.
Cuplikan berikut menunjukkan berbagai cara untuk menentukan item di dalam
LazyColumn
.
Anda dapat memberikan jumlah item:
// Remember to import Glance Composables // import androidx.glance.appwidget.layout.LazyColumn LazyColumn { items(10) { index: Int -> Text( text = "Item $index", modifier = GlanceModifier.fillMaxWidth() ) } }
Berikan item individual:
LazyColumn { item { Text("First Item") } item { Text("Second Item") } }
Berikan daftar atau array item:
LazyColumn { items(peopleNameList) { name -> Text(name) } }
Anda juga dapat menggunakan kombinasi contoh sebelumnya:
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") } }
Perhatikan bahwa cuplikan sebelumnya tidak menentukan itemId
. Menentukan
itemId
membantu meningkatkan performa dan mempertahankan scroll
posisi hingga daftar dan update appWidget
dari Android 12 dan seterusnya (untuk
(misalnya, saat menambahkan atau menghapus item dari daftar). Contoh berikut
menunjukkan cara menentukan itemId
:
items(items = peopleList, key = { person -> person.id }) { person -> Text(person.name) }
Menentukan SizeMode
Ukuran AppWidget
dapat berbeda bergantung pada perangkat, pilihan pengguna, atau peluncur,
sehingga penting untuk menyediakan tata letak yang fleksibel seperti yang dijelaskan dalam
halaman tata letak widget yang fleksibel. Glance menyederhanakan hal ini dengan SizeMode
dan nilai LocalSize
. Bagian berikut menjelaskan tiga
mode.
SizeMode.Single
SizeMode.Single
adalah mode default. Ini menunjukkan bahwa hanya ada satu jenis
konten tersedia; artinya, meskipun ukuran AppWidget
yang tersedia berubah,
ukuran konten tidak berubah.
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 // ... } }
Saat menggunakan mode ini, pastikan bahwa:
- Nilai metadata ukuran minimum dan maksimum ditentukan dengan benar berdasarkan pada ukuran konten.
- Konten cukup fleksibel dalam rentang ukuran yang diharapkan.
Secara umum, Anda harus menggunakan mode ini saat:
a) AppWidget
memiliki ukuran tetap, atau
b) tidak mengubah kontennya saat diubah ukurannya.
SizeMode.Responsive
Mode ini setara dengan menyediakan tata letak responsif, yang memungkinkan
GlanceAppWidget
untuk menentukan serangkaian tata letak responsif yang dibatasi oleh
ukuran. Untuk setiap ukuran yang ditentukan, konten akan dibuat dan dipetakan ke
ukuran saat AppWidget
dibuat atau diupdate. Sistem kemudian memilih
paling cocok berdasarkan ukuran yang tersedia.
Misalnya, dalam AppWidget
tujuan, Anda dapat menentukan tiga ukuran dan
konten:
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") } } } }
Pada contoh sebelumnya, metode provideContent
dipanggil tiga kali dan
dipetakan ke ukuran yang ditentukan.
- Pada panggilan pertama, ukurannya bernilai
100x100
. Konten tidak termasuk tombol tambahan, atau teks atas dan bawah. - Pada panggilan kedua, ukurannya bernilai
250x100
. Konten tersebut mencakup tombol tambahan, tetapi bukan teks atas dan bawah. - Pada panggilan ketiga, ukurannya bernilai
250x250
. Konten tersebut mencakup tombol ekstra dan kedua teks.
SizeMode.Responsive
adalah kombinasi dari dua mode lainnya, dan memungkinkan Anda
menentukan konten responsif dalam batas yang telah ditentukan. Secara umum, mode ini
berperforma lebih baik dan memungkinkan transisi yang lebih halus saat AppWidget
diubah ukurannya.
Tabel berikut menunjukkan nilai ukuran, bergantung pada SizeMode
dan
AppWidget
ukuran yang tersedia:
Ukuran yang tersedia | 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 |
* Nilai tepatnya hanya untuk tujuan demo. |
SizeMode.Exact
SizeMode.Exact
setara dengan menyediakan tata letak yang tepat, yang
meminta konten GlanceAppWidget
setiap kali ukuran AppWidget
yang tersedia
perubahan (misalnya, saat pengguna mengubah ukuran AppWidget
di layar utama).
Misalnya, di widget tujuan, tombol tambahan dapat ditambahkan jika lebar yang tersedia lebih besar dari nilai tertentu.
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") } } } } }
Mode ini memberikan lebih banyak fleksibilitas dibandingkan yang lain, tetapi dilengkapi dengan beberapa peringatan:
AppWidget
harus dibuat ulang sepenuhnya setiap kali ukuran berubah. Ini dapat menyebabkan masalah performa dan UI melonjak saat konten bersifat kompleks.- Ukuran yang tersedia mungkin berbeda bergantung pada implementasi peluncur. Misalnya, jika peluncur tidak menyediakan daftar ukuran, ukuran minimum yang mungkin digunakan.
- Di perangkat pra-Android 12, logika penghitungan ukuran mungkin tidak berfungsi di semua situasi.
Secara umum, Anda harus menggunakan mode ini jika SizeMode.Responsive
tidak dapat digunakan
(yaitu, serangkaian kecil tata letak responsif tidak memungkinkan).
Akses materi
Gunakan LocalContext.current
untuk mengakses resource Android, seperti yang ditunjukkan di
contoh berikut:
LocalContext.current.getString(R.string.glance_title)
Sebaiknya berikan ID aset secara langsung untuk mengurangi ukuran materi akhir
RemoteViews
dan untuk mengaktifkan resource dinamis, seperti dinamis
warna.
Composable dan metode menerima resource menggunakan "penyedia", seperti
ImageProvider
, atau menggunakan metode overload seperti
GlanceModifier.background(R.color.blue)
. Contoh:
Column( modifier = GlanceModifier.background(R.color.default_widget_background) ) { /**...*/ } Image( provider = ImageProvider(R.drawable.ic_logo), contentDescription = "My image", )
Menangani teks
Glance 1.1.0 menyertakan API untuk menyetel gaya teks Anda. Atur gaya teks menggunakan
Atribut fontSize
, fontWeight
, atau fontFamily
dari class TextStyle.
fontFamily
mendukung semua font sistem, seperti yang ditunjukkan dalam contoh berikut, tetapi
font kustom di aplikasi tidak didukung:
Text(
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
fontFamily = FontFamily.Monospace
),
text = "Example Text"
)
Menambahkan tombol gabungan
Tombol gabungan diperkenalkan di Android 12. Sekilas mendukung pembaruan kompatibilitas untuk jenis tombol gabungan berikut:
Tombol gabungan ini masing-masing menampilkan tampilan yang dapat diklik yang mewakili "dicentang" status.
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" )
Saat status berubah, lambda yang disediakan akan dipicu. Anda dapat menyimpan periksa status, seperti yang ditunjukkan dalam contoh berikut:
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) } ) } }
Anda juga dapat memberikan atribut colors
ke CheckBox
, Switch
, dan
RadioButton
untuk menyesuaikan warnanya:
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) ), )
Komponen tambahan
Glance 1.1.0 mencakup rilis komponen tambahan, sebagaimana dijelaskan dalam tabel berikut:
Nama | Gambar | Link referensi | Catatan tambahan |
---|---|---|---|
Tombol Terisi | Komponen | ||
Tombol Outline | Komponen | ||
Tombol Ikon | Komponen | Utama / Sekunder / Hanya ikon | |
Panel Judul | Komponen | ||
Scaffold | Scaffold dan Kolom judul berada dalam demo yang sama. |
Untuk informasi lebih lanjut tentang spesifikasi desain, lihat desain komponen dalam design kit di Figma.