Farklı ekran boyutlarını destekleme

Farklı ekran boyutlarına yönelik destek, uygulamanıza en geniş çeşitlilikte cihazlar ve en fazla sayıda kullanıcı tarafından erişim sağlar.

Mümkün olduğunca çok ekran boyutunu desteklemek için uygulama düzenlerinizi duyarlı ve uyarlanabilir olacak şekilde tasarlayın. Duyarlı/uyarlanabilir düzenler, ekran boyutundan bağımsız olarak optimize edilmiş bir kullanıcı deneyimi sunarak uygulamanızın telefonlar, tabletler, katlanabilir cihazlar, ChromeOS cihazlar, dikey ve yatay yönler ve çoklu pencere modu gibi yeniden boyutlandırılabilir yapılandırmalara uymasını sağlar.

Duyarlı/uyarlanabilir düzenler, kullanılabilir görüntüleme alanına göre değişir. Yapılan değişiklikler, uygulamanızın farklı ekran boyutlarına en iyi şekilde uyum sağlayabilmesi için yer kaplayan küçük düzen düzenlemelerinden (duyarlı tasarım) bir düzeni diğeriyle tamamen değiştirmeye kadar değişiklik gösterir.

Bildirim temelli bir kullanıcı arayüzü araç seti olan Jetpack Compose, içeriği çeşitli ekran boyutlarında farklı şekilde oluşturmak için dinamik olarak değişen düzenler tasarlamak ve uygulamak için idealdir.

Ekran düzeyinde composable'lar için büyük düzen değişikliklerinin uygunsuz olmasını sağlayın

Bir uygulamanın tamamını yerleştirmek için Compose'u kullanırken uygulamanızın oluşturulması için verilen tüm alanı uygulama düzeyinde ve ekran düzeyinde composable'lar kaplar. Tasarımınızda bu düzeyde, daha büyük ekranlardan yararlanmak için bir ekranın genel düzenini değiştirmek mantıklı olabilir.

Düzenle ilgili kararlar verirken fiziksel, donanım değerleri kullanmaktan kaçının. Kararları sabit bir somut değere göre vermek cazip gelebilir (Cihaz bir tablet mi? Fiziksel ekranın belirli bir en boy oranı var mı?), ancak bu soruların yanıtları, kullanıcı arayüzünüzün çalışabileceği alanı belirlemek için faydalı olmayabilir.

Telefon, katlanabilir cihaz, tablet ve dizüstü bilgisayar gibi çeşitli cihaz form faktörlerini gösteren şema.
Şekil 1. Telefon, katlanabilir, tablet ve dizüstü bilgisayar form faktörleri

Tabletlerde bir uygulama çoklu pencere modunda çalışıyor olabilir. Bu da, uygulamanın ekranı başka bir uygulamaya böldüğü anlamına gelir. ChromeOS'te bir uygulama, yeniden boyutlandırılabilir bir pencerede olabilir. Hatta katlanabilir cihaz gibi birden fazla fiziksel ekran bile olabilir. Bunların tümünde, fiziksel ekran boyutu içeriğin nasıl görüntüleneceğine karar verirken dikkate alınmaz.

Bunun yerine, Jetpack WindowManager kitaplığı tarafından sağlanan mevcut pencere metrikleri gibi ekranın uygulamanıza ayrılan gerçek bölümüne göre kararlar almanız gerekir. Bir Compose uygulamasında WindowManager'ın nasıl kullanılacağını görmek için JetNews örneğine göz atın.

Bu yaklaşımı uygulamak, uygulamanızı yukarıdaki senaryoların tümünde iyi davranacağı için daha esnek hale getirir. Düzenlerinizi ekran alanına uygun hale getirmek, ChromeOS gibi platformları ve tabletler ile katlanabilir cihazlar gibi form faktörlerini desteklemek için gereken özel kullanım miktarını da azaltır.

Uygulamanız için kullanılabilir olan ilgili alanı gözlemledikten sonra, Pencere boyutu sınıflarında açıklandığı gibi ham boyutu anlamlı bir boyut sınıfına dönüştürmek faydalıdır. Bu özellik, boyutları standart boyut grupları halinde gruplandırır. Bunlar, en benzersiz durumlar için uygulamanızı optimize etme esnekliği ile basitliği dengelemek üzere tasarlanmış ayırma noktalarıdır. Bu boyut sınıfları, uygulamanızın genel penceresini belirtir. Bu nedenle, genel ekran düzeninizi etkileyen düzen kararlarında bu sınıfları kullanın. Bu boyut sınıflarını durum olarak aktarabilir veya iç içe yerleştirilmiş composable'lara geçirmek üzere türetilmiş durum oluşturmak için ek mantık uygulayabilirsiniz.

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun MyApp(
    windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
) {
    // Perform logic on the size class to decide whether to show the top app bar.
    val showTopAppBar = windowSizeClass.windowHeightSizeClass != WindowHeightSizeClass.COMPACT

    // MyScreen knows nothing about window sizes, and performs logic based on a Boolean flag.
    MyScreen(
        showTopAppBar = showTopAppBar,
        /* ... */
    )
}

Bu katmanlı yaklaşım, ekran boyutu mantığını uygulamanız genelinde senkronize edilmesi gereken birçok yere dağıtmak yerine tek bir konumla sınırlar. Bu tek konum, durumu oluşturur. Bu durum, diğer uygulama durumlarında olduğu gibi, diğer composable'lara açık bir şekilde aktarılabilir. Durumun açıkça iletilmesi, tek tek composable'ları basitleştirir. Çünkü bunlar, diğer verilerle birlikte boyut sınıfını veya belirtilen yapılandırmayı alan normal composable işlevler olacaktır.

Esnek, iç içe yerleştirilmiş composable'lar yeniden kullanılabilir

Composable'lar çok çeşitli yerlere yerleştirildiklerinde daha fazla tekrar kullanılabilir durumdadır. Bir composable, her zaman belirli bir boyutla belirli bir konuma yerleştirileceğini varsayarsa onu farklı bir yerde ya da farklı miktarda alanla yeniden kullanmak daha zor olur. Bu aynı zamanda, bağımsız, yeniden kullanılabilir composable'ların "genel" boyut bilgilerine dolaylı olarak bağlı kalmaması gerektiği anlamına gelir.

Şu örneği düşünün: Bir bölmeyi yan yana gösterebilen liste ayrıntıları düzeni uygulayan, iç içe yerleştirilmiş bir composable düşünün.

İki bölmeyi yan yana gösteren bir uygulama ekran görüntüsü.
Şekil 2. Tipik bir liste ayrıntısı düzenini gösteren uygulamanın ekran görüntüsü: 1 liste alanı, 2 ise ayrıntı alanıdır.

Bu kararın, uygulamanın genel düzeninin bir parçası olmasını istiyoruz. Bu nedenle, yukarıda gördüğümüz gibi ekran düzeyinde bir composable'a ait kararı iletiyoruz:

@Composable
fun AdaptivePane(
    showOnePane: Boolean,
    /* ... */
) {
    if (showOnePane) {
        OnePane(/* ... */)
    } else {
        TwoPane(/* ... */)
    }
}

Bunun yerine bir composable'ın, düzenini mevcut alana göre bağımsız olarak değiştirmesini istersek ne olur? Örneğin, alan izin veriyorsa ek ayrıntıları göstermek isteyen bir kart kullanabilirsiniz. Mevcut bazı boyutlara göre bazı mantık gerçekleştirmek istiyoruz, ama özellikle hangi boyut?

İki farklı kart örneği.
Şekil 3. Yalnızca bir simge ve başlığın yer aldığı dar kart ile simge, başlık ve kısa açıklamayı gösteren daha geniş bir kart.

Yukarıda gördüğümüz gibi, cihazın gerçek ekran boyutunu kullanmaya çalışmaktan kaçınmamız gerekir. Bu, birden fazla ekran için doğru olmaz ve uygulama tam ekran değilse ayrıca doğru olmaz.

composable, ekran düzeyinde composable olmadığından, yeniden kullanılabilirliği en üst düzeye çıkarmak için geçerli pencere metriklerini de doğrudan kullanmamalıyız. Bileşen dolguyla yerleştiriliyorsa (iç kısımlar gibi) veya gezinme rayları ya da uygulama çubukları gibi bileşenler varsa composable için kullanılabilen alan, uygulamanın toplam alanından önemli ölçüde farklı olabilir.

Bu nedenle, composable'ın aslında kendisini oluşturmak için verildiği genişliği kullanmalıyız. Bu genişliği elde etmek için iki seçeneğimiz vardır:

İçeriğin nerede veya nasıl gösterildiğini değiştirmek isterseniz düzeni duyarlı hale getirmek için bir değiştiriciler koleksiyonu veya özel düzen kullanabilirsiniz. Bu, mevcut tüm alanı küçük bir çocuğun doldurması veya yeterli alan varsa çocukları birden fazla sütuna yerleştirmek gibi basit bir yaklaşım olabilir.

Gösterdiğiniz öğeyi değiştirmek istiyorsanız, daha güçlü bir alternatif olarak BoxWithConstraints kullanabilirsiniz. Bu composable, kullanılabilir alana göre farklı composable'ları çağırmak için kullanabileceğiniz ölçüm kısıtlamaları sunar. Ancak BoxWithConstraints, bu kısıtlamaların bilindiği ve düzen sırasında daha fazla iş yapılmasının sağlandığı Düzen aşamasına kadar besteyi ertelediğinden, bunun bir maliyeti vardır.

@Composable
fun Card(/* ... */) {
    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(/* ... */)
                Title(/* ... */)
            }
        } else {
            Row {
                Column {
                    Title(/* ... */)
                    Description(/* ... */)
                }
                Image(/* ... */)
            }
        }
    }
}

Tüm verilerin farklı boyutlar için kullanılabildiğinden emin olun

Ek ekran alanından yararlanırken, büyük bir ekranda kullanıcıya küçük bir ekrana göre daha fazla içerik gösterebilirsiniz. Bu davranışa sahip bir composable'ı uygularken verim almak ve verileri mevcut boyutun yan etkisi olarak yüklemek cazip gelebilir.

Ancak bu, verilerin uygun şekilde oluşturulması için toplanıp composable'lara sağlandığı tek yönlü veri akışı ilkelerine aykırıdır. Verilerin bir kısmı her zaman kullanılmasa bile composable'ın tüm boyutlarda göstermesi gereken özelliklere sahip olması için composable'a yeterli miktarda veri sağlanmalıdır.

@Composable
fun Card(
    imageUrl: String,
    title: String,
    description: String
) {
    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(imageUrl)
                Title(title)
            }
        } else {
            Row {
                Column {
                    Title(title)
                    Description(description)
                }
                Image(imageUrl)
            }
        }
    }
}

Card örneğine dayanarak, description öğesinin her zaman Card öğesine iletildiğini unutmayın. description yalnızca genişlik gösterilmesine izin verdiğinde kullanılsa da Card, kullanılabilir genişlikten bağımsız olarak her zaman için gereklidir.

Her zaman iletilen veriler, uyarlanabilir düzenleri daha az durum bilgili hale getirerek daha basit hale getirir ve boyutlar arasında geçiş yaparken yan etkilerin tetiklenmesini önler (pencere yeniden boyutlandırması, yön değişikliği veya cihazın katlanıp genişletilmesi nedeniyle olabilir).

Bu ilke aynı zamanda düzen değişikliklerinde durumun korunmasına da olanak tanır. Tüm boyutlarda kullanılmayabilecek bilgileri kaldırarak düzen boyutu değiştiğinde kullanıcının durumunu koruyabiliriz. Örneğin, yeniden boyutlandırmalar düzenin gizleme ve açıklamayı gösterme arasında geçiş yapmasına neden olduğunda kullanıcının durumunun korunması için bir showMore Boole işaretini kaldırabiliriz:

@Composable
fun Card(
    imageUrl: String,
    title: String,
    description: String
) {
    var showMore by remember { mutableStateOf(false) }

    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(imageUrl)
                Title(title)
            }
        } else {
            Row {
                Column {
                    Title(title)
                    Description(
                        description = description,
                        showMore = showMore,
                        onShowMoreToggled = { newValue ->
                            showMore = newValue
                        }
                    )
                }
                Image(imageUrl)
            }
        }
    }
}

Daha fazla bilgi

Compose'daki özel düzenler hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara başvurun.

Örnek uygulamalar

  • Büyük ekran standart düzenleri, büyük ekranlı cihazlarda optimum kullanıcı deneyimi sağlayan, etkisi kanıtlanmış tasarım kalıplarından oluşan bir depodur.
  • JetNews, kullanıcı arayüzünü mevcut alandan yararlanacak şekilde uyarlayan bir uygulamanın nasıl tasarlanacağını gösteriyor
  • Reply mobil cihazlar, tabletler ve katlanabilir cihazları desteklemek için uyarlanabilir bir örnektir
  • Now in Android, farklı ekran boyutlarını desteklemek için

Videolar