Klasy rozmiarów okna to zestaw punktów przecięcia widocznego obszaru, które pomagają projektować, tworzyć i testować elastyczne lub adaptacyjne układy. Punkty graniczne zapewniają równowagę między prostotą układu a elastycznością optymalizacji aplikacji pod kątem wyjątkowych przypadków.
Klasy rozmiarów okna dzielą obszar wyświetlania dostępny dla aplikacji na kompaktowy, średni i rozwinięty. Dostępna szerokość i wysokość są klasyfikowane osobno, więc w dowolnym momencie aplikacja ma 2 klasy rozmiarów okna: jedną dla szerokości i jedną dla wysokości. Dostępna szerokość jest zwykle ważniejsza niż dostępna wysokość ze względu na powszechność przewijania w poziomie, dlatego klasa rozmiaru okna pod względem szerokości jest prawdopodobnie bardziej odpowiednia dla interfejsu aplikacji.
![](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/adaptive/window-size-classes/window_size_classes_width.png?hl=pl)
![](https://developer.android.google.cn/static/develop/ui/compose/images/layouts/adaptive/window-size-classes/window_size_classes_height.png?hl=pl)
Jak widać na rysunkach, punkty graniczne pozwalają nadal myśleć o układach w kategoriach urządzeń i ich konfiguracji. Każdy punkt przecięcia klasy rozmiaru reprezentuje większość przypadków typowych scenariuszy dotyczących urządzeń. Może to być przydatne podczas projektowania układów opartych na punktach przecięcia.
Klasa rozmiaru | Punkt przerwania | Reprezentacja urządzenia |
---|---|---|
Szerokość kompaktowa | szerokość < 600 dp | 99,96% telefonów w układzie pionowym |
Średnia szerokość | 600 dp ≤ szerokość < 840 dp | 93,73% tabletów w orientacji pionowej,
większość dużych rozłożonych wewnętrznych ekranów w orientacji pionowej |
Szerokość po rozwinięciu | szerokość ≥ 840 dp | 97,22% tabletów w orientacji poziomej,
największe rozłożone wyświetlacze wewnętrzne w układzie poziomym |
Kompaktowa wysokość | height < 480dp | 99,78% telefonów w orientacji poziomej |
Średnia wysokość | 480 dp ≤ wysokość < 900 dp | 96,56% tabletów w orientacji poziomej,
97,59% telefonów w orientacji pionowej |
Wysokość po rozwinięciu | wysokość ≥ 900 dp | 94,25% tabletów w orientacji pionowej |
Wizualizacja klas wielkości jako urządzeń fizycznych może być przydatna, ale klasy rozmiarów okien nie są określane przez rozmiar ekranu urządzenia. Klasy rozmiaru okna nie są przeznaczone do logiki typu isTablet. Klasy rozmiarów okien są określane na podstawie rozmiaru okna dostępnego dla aplikacji niezależnie od typu urządzenia, na którym aplikacja działa. Ma to 2 ważne konsekwencje:
Urządzenia fizyczne nie gwarantują określonej klasy rozmiaru okna. Miejsce na ekranie dostępne dla aplikacji może się różnić od rozmiaru ekranu urządzenia z wielu powodów. Na urządzeniach mobilnych tryb podzielonego ekranu może podzielić ekran na 2 aplikacje. W ChromeOS aplikacje na Androida mogą być wyświetlane w oknach typu desktop, które można dowolnie zmieniać. Urządzenia składane mogą mieć 2 ekrany o różnych rozmiarach, do których można uzyskać dostęp, składając lub rozkładając urządzenie.
Klasa rozmiaru okna może się zmieniać w trakcie działania aplikacji.Podczas jej działania zmiana orientacji urządzenia, korzystanie z wielu aplikacji jednocześnie oraz składanie i rozkładanie mogą wpływać na ilość dostępnej przestrzeni na ekranie. W rezultacie klasa rozmiaru okna jest dynamiczna, a interfejs aplikacji powinien się odpowiednio dostosować.
Klasy rozmiarów okien odpowiadają punktom przerwania w układówce Material Design w wersji kompaktowej, średniej i rozwiniętej. Klasy rozmiarów okien umożliwiają podejmowanie ogólnych decyzji dotyczących układu aplikacji, na przykład decyzji, czy użyć określonego kanonicznego układu, aby wykorzystać dodatkową przestrzeń ekranu.
Możesz obliczyć bieżącą
WindowSizeClass
za pomocą
WindowSizeClass#compute()
funkcja dostępna w Jetpack
WindowManager. Przykład poniżej
pokazuje, jak obliczyć klasę rozmiaru okna i otrzymywać aktualizacje za każdym razem,
zmiany klasy rozmiaru okna:
Kotlin
class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. val container: ViewGroup = binding.container // Add a utility view to the container to hook into // View.onConfigurationChanged(). This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged(), // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged() is // called in those scenarios. container.addView(object : View(this) { override fun onConfigurationChanged(newConfig: Configuration?) { super.onConfigurationChanged(newConfig) computeWindowSizeClasses() } }) computeWindowSizeClasses() } private fun computeWindowSizeClasses() { val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(this) val width = metrics.bounds.width() val height = metrics.bounds.height() val density = resources.displayMetrics.density val windowSizeClass = WindowSizeClass.compute(width/density, height/density) // COMPACT, MEDIUM, or EXPANDED val widthWindowSizeClass = windowSizeClass.windowWidthSizeClass // COMPACT, MEDIUM, or EXPANDED val heightWindowSizeClass = windowSizeClass.windowHeightSizeClass // Use widthWindowSizeClass and heightWindowSizeClass. } }
Java
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. ViewGroup container = binding.container; // Add a utility view to the container to hook into // View.onConfigurationChanged(). This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged(), // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged() is // called in those scenarios. container.addView(new View(this) { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); computeWindowSizeClasses(); } }); computeWindowSizeClasses(); } private void computeWindowSizeClasses() { WindowMetrics metrics = WindowMetricsCalculator.getOrCreate() .computeCurrentWindowMetrics(this); int width = metrics.getBounds().width int height = metrics.getBounds().height() float density = getResources().getDisplayMetrics().density; WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density) // COMPACT, MEDIUM, or EXPANDED WindowWidthSizeClass widthWindowSizeClass = windowSizeClass.getWindowWidthSizeClass() // COMPACT, MEDIUM, or EXPANDED WindowHeightSizeClass heightWindowSizeClass = windowSizeClass.getWindowHeightSizeClass() // Use widthWindowSizeClass and heightWindowSizeClass. } }
Testowanie klas rozmiarów okien
W miarę wprowadzania zmian w układzie testuj jego działanie w przypadku wszystkich rozmiarów okna, szczególnie w przypadku szerokości punktów przełamania w ustawieniach „Kompaktowy”, „Średni” i „Rozwinięty”.
Jeśli masz już układ dla ekranów kompaktowych, najpierw zoptymalizuj go pod kątem klasy rozmiaru z rozszerzoną szerokością, ponieważ ta klasa rozmiaru zapewnia najwięcej miejsca na dodatkowe treści i zmiany interfejsu. Następnie zdecyduj, jaki układ jest odpowiedni dla klasy średniej szerokości; rozważ dodanie układu specjalistycznego.
Dalsze kroki
Więcej informacji o używaniu klas rozmiarów okien do tworzenia responsywnych/adaptacyjnych układów znajdziesz w tych artykułach:
Układy oparte na edytorze: obsługa różnych rozmiarów wyświetlania
W przypadku układów opartych na widoku: elastyczny/adaptacyjny projekt z widokami.
Aby dowiedzieć się więcej o tym, co sprawia, że aplikacja działa świetnie na wszystkich urządzeniach i ekranach, przeczytaj: