Klasy rozmiarów okien to zestaw opartych na opiniach punktów przerwania widocznego obszaru, które pomagają projektować, tworzyć i testować elastyczne/adaptacyjne układy. Punkty przerwania łączą prostotę układu z elastycznością optymalizacji aplikacji pod kątem unikalnych przypadków.
Klasy rozmiaru okna dzielą obszar wyświetlania dostępny dla aplikacji na kompaktowy, średni, rozszerzony, duży i bardzo duży. Dostępna szerokość i wysokość są klasyfikowane osobno, więc w każdym momencie aplikacja ma 2 klasy rozmiaru 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 pionie, więc klasa rozmiaru okna szerokości jest prawdopodobnie bardziej istotna dla interfejsu aplikacji.


Jak widać na ilustracjach, punkty przerwania pozwalają nadal myśleć o układach w kategoriach urządzeń i konfiguracji. Każdy punkt przerwania klasy rozmiaru reprezentuje większość typowych scenariuszy urządzeń, co może być przydatnym punktem odniesienia podczas projektowania układów opartych na punktach przerwania.
Klasa rozmiaru | Punkt przerwania | Reprezentacja urządzenia |
---|---|---|
Szerokość w trybie kompaktowym | width < 600dp | 99,96% telefonów w trybie pionowym |
Średnia szerokość | 600 dp ≤ szerokość < 840 dp | 93,73% tabletów w orientacji pionowej,
większość dużych rozłożonych ekranów wewnętrznych w orientacji pionowej, |
Szerokość po rozwinięciu | 840dp ≤ szerokość < 1200dp | 97,22% tabletów w orientacji poziomej,
większość dużych rozłożonych ekranów wewnętrznych w orientacji poziomej ma co najmniej rozszerzoną szerokość. |
Duża szerokość | 1200 dp ≤ szerokość < 1600 dp | Duże wyświetlacze tabletów |
Bardzo duża szerokość | szerokość ≥ 1600 dp | Reklamy displayowe na komputery |
Wysokość po złożeniu | 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 | height ≥ 900dp | 94,25% tabletów w orientacji pionowej |
Chociaż wizualizacja klas rozmiarów jako urządzeń fizycznych może być przydatna, klasy rozmiarów okien nie są określane przez rozmiar ekranu urządzenia. Klasy rozmiaru okna nie są przeznaczone do logiki typu isTablet. Klasy rozmiaru okna są określane na podstawie rozmiaru okna dostępnego dla aplikacji niezależnie od typu urządzenia, na którym jest ona uruchomiona. Ma to 2 ważne konsekwencje:
Urządzenia fizyczne nie gwarantują określonej klasy rozmiaru okna. Przestrzeń ekranu dostępna dla aplikacji może różnić się od rozmiaru ekranu urządzenia z wielu powodów. Na urządzeniach mobilnych tryb podzielonego ekranu może dzielić ekran między 2 aplikacje. W ChromeOS aplikacje na Androida mogą być wyświetlane w oknach typu desktop, których rozmiar można dowolnie zmieniać. Urządzenia składane mogą mieć 2 ekrany o różnych rozmiarach, do których można uzyskać dostęp osobno, składając lub rozkładając urządzenie.
Klasa rozmiaru okna może się zmieniać w trakcie działania aplikacji. Podczas działania aplikacji zmiany orientacji urządzenia, wielozadaniowość i składanie/rozkładanie mogą zmieniać ilość dostępnego miejsca na ekranie. W rezultacie klasa rozmiaru okna jest dynamiczna, a interfejs aplikacji powinien się do niej dostosowywać.
Klasy rozmiaru okna odpowiadają punktom przerwania „compact”, „medium” i „expanded” w wytycznych dotyczących układu Material Design. Używaj klas rozmiaru okna, aby podejmować decyzje dotyczące układu aplikacji na wysokim poziomie, np. decydować, czy używać określonego układu kanonicznego, aby wykorzystać dodatkową przestrzeń na ekranie.
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
Wprowadzając zmiany w układzie, testuj jego działanie we wszystkich rozmiarach okna, zwłaszcza przy szerokościach punktów przerwania dla układu kompaktowego, średniego i rozszerzonego.
Jeśli masz już układ dla kompaktowych ekranów, najpierw zoptymalizuj go pod kątem klasy rozmiaru o większej szerokości, ponieważ ta klasa rozmiaru zapewnia najwięcej miejsca na dodatkowe treści i zmiany interfejsu. Następnie zdecyduj, który układ będzie odpowiedni dla klasy rozmiaru o średniej szerokości. Możesz dodać specjalny układ.
Dalsze kroki
Więcej informacji o korzystaniu z klas rozmiaru okna do tworzenia elastycznych układów znajdziesz w tych artykułach:
W przypadku układów opartych na Compose: obsługa różnych rozmiarów wyświetlania.
W przypadku układów opartych na widokach: elastyczne/adaptacyjne projektowanie z widokami
Więcej informacji o tym, co sprawia, że aplikacja jest świetna na wszystkich urządzeniach i ekranach o różnych rozmiarach, znajdziesz w tych artykułach: