Używanie klas rozmiarów okien

Wypróbuj tworzenie wiadomości
Jetpack Compose to zalecany zestaw narzędzi interfejsu na Androida. Dowiedz się, jak korzystać z klas rozmiaru okna w Compose.

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, średnirozwinię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.

Rysunek 1. Reprezentacje klas rozmiarów okien na podstawie szerokości.
Rysunek 2. Reprezentacje klas rozmiarów okien na podstawie ich wysokości.

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:

Aby dowiedzieć się więcej o tym, co sprawia, że aplikacja działa świetnie na wszystkich urządzeniach i ekranach, przeczytaj: