Z tej strony dowiesz się, jak obsługiwać rozmiary oraz stosować elastyczne i elastyczne elementy układy graficzne z użyciem istniejących komponentów W skrócie.
Użyj usług Box
, Column
i Row
Funkcja Glance ma 3 główne układy kompozycyjne:
Box
: powoduje umieszczenie elementów na drugim. To przekłada się naRelativeLayout
.Column
: powoduje umieszczanie elementów po sobie na osi pionowej. Tłumaczy doLinearLayout
w orientacji pionowej.Row
: powoduje umieszczenie elementów po sobie na osi poziomej. Tłumaczy doLinearLayout
w orientacji poziomej.
Funkcja W skrócie obsługuje obiekty Scaffold
. Umieść: Column
, Row
i
Elementy kompozycyjne: Box
w obrębie danego obiektu Scaffold
.
Każdy z tych elementów kompozycyjnych pozwala określić wyrównanie w pionie i poziomie. jej zawartości oraz ograniczeń dotyczących szerokości, wysokości, wagi lub dopełnienia za pomocą funkcji modyfikatory. Dodatkowo każde wydawca podrzędny może zdefiniować swój modyfikator, aby zmienić pokój i umiejscowienie w środku elementu nadrzędnego.
Ten przykład pokazuje, jak utworzyć Row
równomiernie rozłożony
jego elementy podrzędne poziomo, tak jak na rys. 1:
Row(modifier = GlanceModifier.fillMaxWidth().padding(16.dp)) { val modifier = GlanceModifier.defaultWeight() Text("first", modifier) Text("second", modifier) Text("third", modifier) }
Element Row
wypełnia maksymalną dostępną szerokość, a ponieważ każde z nich ma taką samą szerokość
będą równomiernie dzielić dostępne miejsce. Możesz zdefiniować różne wagi,
rozmiary, dopełnienia i wyrównania, aby dostosować układy do swoich potrzeb.
Używaj układów z możliwością przewijania
Innym sposobem na dostarczanie elastycznych treści jest umożliwienie ich przewijania. To jest
dzięki funkcji kompozycyjnej LazyColumn
. Ta funkcja kompozycyjna pozwala zdefiniować zbiór
elementów do wyświetlania w przewijanym kontenerze w widżecie aplikacji.
Poniższe fragmenty kodu pokazują różne sposoby definiowania elementów wewnątrz
LazyColumn
Możesz podać liczbę elementów:
// Remember to import Glance Composables // import androidx.glance.appwidget.layout.LazyColumn LazyColumn { items(10) { index: Int -> Text( text = "Item $index", modifier = GlanceModifier.fillMaxWidth() ) } }
Podaj poszczególne elementy:
LazyColumn { item { Text("First Item") } item { Text("Second Item") } }
Podaj listę lub tablicę elementów:
LazyColumn { items(peopleNameList) { name -> Text(name) } }
Możesz też wykorzystać kombinację powyższych przykładów:
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") } }
Pamiętaj, że poprzedni fragment kodu nie zawiera elementu itemId
. Określanie parametru
itemId
pomaga poprawić wydajność i utrzymać przewijanie
pozycji na liście i aktualizacji appWidget
od Androida 12 (na
np. podczas dodawania lub usuwania elementów z listy). Przykład poniżej
pokazuje, jak określić itemId
:
items(items = peopleList, key = { person -> person.id }) { person -> Text(person.name) }
Zdefiniuj SizeMode
Rozmiary AppWidget
mogą się różnić w zależności od urządzenia, wyboru użytkownika lub programu uruchamiającego,
dlatego ważne jest, by zapewnić elastyczne układy, tak jak to opisano w narzędziu
do elastycznych układów widżetów. Uprość to za pomocą funkcji Glance, używając SizeMode
definicji i wartości LocalSize
. W kolejnych sekcjach opisano 3 z nich:
i trybów wyświetlania.
SizeMode.Single
SizeMode.Single
to tryb domyślny. Wskazuje on, że tylko jeden typ
została udostępniona, czyli nawet jeśli dostępny AppWidget
rozmiar się zmieni,
rozmiar treści się nie zmienia.
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 // ... } }
Podczas korzystania z tego trybu upewnij się, że:
- Minimalny i maksymalny rozmiar wartości metadanych są prawidłowo zdefiniowane, na rozmiar treści.
- Treść jest wystarczająco elastyczna i mieści się w oczekiwanym zakresie rozmiarów.
Ogólnie należy używać tego trybu, gdy:
a) AppWidget
ma stały rozmiar lub
b) nie zmienia swojej zawartości po zmianie rozmiaru.
SizeMode.Responsive
Ten tryb jest odpowiednikiem udostępniania układów elastycznych, co pozwala
GlanceAppWidget
, by zdefiniować zestaw układów elastycznych ograniczonych
rozmiarów reklam Google Ads. W przypadku każdego zdefiniowanego rozmiaru treść jest tworzona i zmapowana na określony
rozmiaru podczas tworzenia lub aktualizacji elementu AppWidget
. System wybiera wtedy
najlepiej dopasowanego na podstawie dostępnego rozmiaru.
Na przykład w miejscu docelowym AppWidget
możesz zdefiniować trzy rozmiary i
treść:
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") } } } }
W poprzednim przykładzie metoda provideContent
jest wywoływana 3 razy.
mapowane na zdefiniowany rozmiar.
- Przy pierwszym wywołaniu rozmiar przyjmuje wartość
100x100
. Nie są one zgodne zawierać dodatkowy przycisk ani tekst na górze i na dole. - W drugim wywołaniu rozmiar przyjmuje wartość
250x100
. Są to między innymi: dodatkowego przycisku, ale nie tekstu na górze i na dole. - W trzecim wywołaniu rozmiar przyjmuje wartość
250x250
. Są to między innymi: dodatkowego przycisku i obu tekstów.
SizeMode.Responsive
to połączenie 2 pozostałych trybów i umożliwia:
tworzyć elastyczne treści
w zdefiniowanych wcześniej granicach. Ogólnie ten tryb
działa lepiej i umożliwia płynniejsze przejścia po zmianie rozmiaru elementu AppWidget
.
W tabeli poniżej znajdziesz wartość rozmiaru w zależności od tych atrybutów: SizeMode
AppWidget
dostępny rozmiar:
Dostępny rozmiar | 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 |
* Dokładne wartości są podane tylko w celach demonstracyjnych. |
SizeMode.Exact
SizeMode.Exact
jest odpowiednikiem podawania dokładnych układów, które
żąda treści GlanceAppWidget
za każdym razem, gdy dostępny rozmiar AppWidget
zmian (na przykład gdy użytkownik zmieni rozmiar elementu AppWidget
na ekranie głównym).
Na przykład w widżecie docelowym można dodać dodatkowy przycisk, jeśli dostępna szerokość jest większa od określonej wartości.
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") } } } } }
Ten tryb zapewnia większą elastyczność niż pozostałe, ale oferuje kilka zastrzeżenia:
- Przy każdej zmianie rozmiaru element
AppWidget
musi być całkowicie odtworzony. Ten może prowadzić do problemów z wydajnością i skoków interfejsu, gdy treść witryny jest skomplikowana. - Dostępny rozmiar może się różnić w zależności od implementacji programu uruchamiającego. Jeśli na przykład program uruchamiający nie podaje listy rozmiarów, minimalna wartość możliwy rozmiar.
- Na urządzeniach z Androidem 12 lub starszym logika obliczania rozmiaru może nie działać w różnych sytuacjach.
Ogólnie należy używać tego trybu, jeśli nie można użyć usługi SizeMode.Responsive
(np. zastosowanie niewielkiego zestawu układów elastycznych jest niemożliwe).
Dostęp do zasobów
Użyj kodu LocalContext.current
, aby uzyskać dostęp do wszystkich zasobów Androida, tak jak to pokazuje
następujący przykład:
LocalContext.current.getString(R.string.glance_title)
Zalecamy bezpośrednie podanie identyfikatorów zasobów, aby zmniejszyć rozmiar ostatecznej
RemoteViews
i włączyć zasoby dynamiczne, takie jak dynamiczne
Elementy kompozycyjne i metody akceptują zasoby korzystające z usług „dostawcy”, takich jak
ImageProvider
lub użycie metody przeciążenia takiej jak
GlanceModifier.background(R.color.blue)
Na przykład:
Column( modifier = GlanceModifier.background(R.color.default_widget_background) ) { /**...*/ } Image( provider = ImageProvider(R.drawable.ic_logo), contentDescription = "My image", )
Tekst uchwytu
Glance 1.1.0 zawiera interfejs API do ustawiania stylów tekstu. Ustaw style tekstu za pomocą:
Atrybuty fontSize
, fontWeight
i fontFamily
klasy TextStyle.
fontFamily
obsługuje wszystkie czcionki systemowe, jak w przykładzie poniżej, ale
czcionki niestandardowe w aplikacjach nie są obsługiwane:
Text(
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
fontFamily = FontFamily.Monospace
),
text = "Example Text"
)
Dodaj przyciski złożone
Złożone przyciski zostały wprowadzone w Androidzie 12. Spojrzenie w tył z tymi typami przycisków złożonych:
Każdy z tych przycisków złożonych wyświetla klikalny widok, który przedstawia „zaznaczone” stanu.
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" )
Po zmianie stanu uruchomiona jest lambda. Możesz przechowywać jak w tym przykładzie:
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) } ) } }
Możesz też podać atrybut colors
w elementach CheckBox
, Switch
i
RadioButton
, aby dostosować kolory:
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) ), )
Dodatkowe komponenty
Glance 1.1.0 obejmuje udostępnienie dodatkowych komponentów, zgodnie z ta tabela:
Nazwa | Obraz | Link referencyjny | Uwagi dodatkowe |
---|---|---|---|
Wypełniony przycisk | Komponent | ||
Przyciski z konspektem | Komponent | ||
Przyciski ikon | Komponent | Główne / Dodatkowe / Tylko ikony | |
Pasek tytułu | Komponent | ||
Ruszt | Ruszt i pasek tytułu są w tej samej wersji demonstracyjnej. |
Więcej informacji o projektach komponentów znajdziesz w tym zestaw projektowy na Figma.