Klasy rozmiaru okna to zestaw sprawdzonych punktów przerwania widocznego obszaru, który pomaga w projektowaniu, tworzeniu i testowaniu układów elastycznych/adaptacyjnych. Punkty przerwania równoważą prosty układ z elastycznością optymalizacji aplikacji pod kątem unikalnych przypadków.
Klasy rozmiaru okna dzielą dostępne dla Twojej aplikacji obszary wyświetlania jako kompaktowe, średnie i rozszerzone. Dostępne szerokości i wysokości są klasyfikowane oddzielnie, więc w każdej chwili aplikacja ma 2 klasy rozmiaru okna – jedną dla szerokości i wysokości. Dostępna szerokość jest zwykle ważniejsza niż dostępna wysokość ze względu na wszechobecność przewijania w pionie – klasa „width” (szerokość okna) prawdopodobnie lepiej pasuje do interfejsu aplikacji.
Jak widać na rysunkach, punkty przerwania pozwalają dalej myśleć o układzie urządzeń i konfiguracji. Każdy punkt przerwania klasy rozmiaru odpowiada większości typowych scenariuszy z urządzeniami, co może być punktem odniesienia przy konstruowaniu układów opartych na tych punktach.
Klasa rozmiaru | Punkt przerwania | Reprezentacja urządzenia |
---|---|---|
Kompaktowa szerokość | szerokość < 600 dp | 99,96% telefonów w orientacji pionowej |
Średnia szerokość | 600 dp ≤ szerokość < 840 dp | 93,73% tabletów jest w orientacji pionowej.
najbardziej duże po rozłożeniu wewnętrzne wyświetlacze w orientacji pionowej |
Szerokość po rozwinięciu | szerokość ≥ 840 dp | 97,22% tabletów w orientacji poziomej.
najbardziej duże po rozłożeniu wewnętrzne wyświetlacze w orientacji poziomej |
Kompaktowa wysokość | wysokość < 480 dp | 99,78% telefonów wyświetla się w orientacji poziomej |
Średni wzrost | 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 |
Chociaż wizualizowanie klas rozmiarów jako urządzeń fizycznych może być przydatne, klasy rozmiaru okna nie są bezpośrednio określane przez rozmiar ekranu urządzenia. Klasy rozmiaru okna nie są przeznaczone dla logiki typu isTablet. Klasy rozmiaru okna są natomiast określane na podstawie rozmiaru okna dostępnego dla aplikacji niezależnie od typu urządzenia, na którym działa aplikacja, co ma 2 ważne konsekwencje:
Urządzenia fizyczne nie gwarantują określonej klasy rozmiaru okna. Miejsce na ekranie dostępne dla aplikacji może z wielu powodów różnić się od rozmiaru ekranu urządzenia. Na urządzeniach mobilnych tryb podzielonego ekranu może partycjonować ekran między 2 aplikacjami. W ChromeOS aplikacje na Androida mogą wyświetlać się w swobodnych oknach, których rozmiar można dowolnie zmieniać. Urządzenia składane mogą mieć 2 ekrany w różnych rozmiarach. Dostęp można uzyskać po złożeniu lub rozłożeniu urządzenia.
Klasa rozmiaru okna może zmieniać się przez cały czas używania aplikacji. Ilość dostępnego miejsca na ekranie może zmieniać się przez cały czas używania aplikacji, wykonywanie wielu zadań jednocześnie oraz wykonywanie innych zadań na urządzeniu. W efekcie klasa rozmiaru okna jest dynamiczna, a interfejs aplikacji powinien odpowiednio się dostosowywać.
Klasy rozmiaru okna są mapowane na kompaktowe, średnie i rozwinięte punkty przerwania zgodnie z wskazówkami dotyczącymi układu Material Design. Używaj klas rozmiaru okna, aby podejmować ogólne decyzje dotyczące układu aplikacji, np. określać, czy użyć określonego układu kanonicznego, aby wykorzystać dodatkowe miejsce na ekranie.
Bieżąca wartość WindowSizeClass
możesz obliczyć za pomocą funkcji WindowSizeClass#compute()
dostępnej w bibliotece Jetpack WindowManager. Z przykładu poniżej dowiesz się, jak obliczyć klasę rozmiaru okna i otrzymywać aktualizacje po każdej zmianie 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. } }
Testowe klasy rozmiaru okna
Wprowadzając zmiany układu, przetestuj jego działanie we wszystkich rozmiarach okien, zwłaszcza przy małej, średniej i rozwiniętej szerokości punktów przerwania.
Jeśli masz już układ dostosowany do kompaktowych ekranów, najpierw zoptymalizuj układ pod kątem klasy rozmiaru rozwiniętej szerokości, ponieważ ta klasa zapewnia najwięcej miejsca na dodatkowe treści i zmiany interfejsu. Następnie zdecyduj, jaki układ będzie odpowiedni dla klasy średniej szerokości i zastanów się nad dodaniem specjalistycznego układu.
Dalsze kroki
Więcej informacji o używaniu klas rozmiaru okna do tworzenia układów elastycznych lub adaptacyjnych znajdziesz w tych artykułach:
W przypadku układów opartych na tworzeniu wiadomości: obsługa różnych rozmiarów ekranu.
Układy oparte na widokach: projektowanie elastyczne/adaptacyjne z widokami
Więcej informacji o zaletach aplikacji na wszystkich urządzeniach i ekranach znajdziesz w tych artykułach: