Farklı ekran boyutlarını destekleme

Farklı ekran boyutlarını desteklemek, uygulamanıza en geniş cihaz çeşitliliğinden ve en fazla sayıda kullanıcıdan erişim sağlar.

Mümkün olduğunca fazla 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 sunar. Böylece uygulamanız telefonlar, tabletler, katlanabilir cihazlar, ChromeOS cihazlar, dikey ve yatay yönler ve çoklu pencere modu gibi yeniden boyutlandırılabilir yapılandırmalara uyum sağlayabilir.

Duyarlı/uyarlanabilir düzenler, mevcut ekran alanına göre değişir. Değişiklikler, alanı dolduran küçük düzen ayarlarından (duyarlı tasarım) uygulamanızın farklı ekran boyutlarına en iyi şekilde uyum sağlayabilmesi için bir düzenin tamamen başka bir düzenle değiştirilmesine (uyarlanabilir tasarım) kadar çeşitlilik gösterir.

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

Ekran düzeyindeki kompozisyonlar için büyük düzen değişikliklerini açıkça belirtin

Bir uygulamanın tamamını tasarlamak için Compose'u kullandığınızda uygulama düzeyindeki ve ekran düzeyindeki bileşenler, uygulamanızın oluşturması için verilen tüm alanı kaplar. Tasarımınızda bu düzeyde, daha büyük ekranlardan yararlanmak için ekranın genel düzenini değiştirmek mantıklı olabilir.

Düzenleme kararları almak için fiziksel, donanım değerleri kullanmaktan kaçının. Sabit ve somut bir değere (Cihaz 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 yararlı olmayabilir.

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

Tabletlerde bir uygulama, çoklu pencere modunda çalışıyor olabilir. Bu durumda uygulama, ekranı başka bir uygulamayla paylaşıyor olabilir. ChromeOS'te bir uygulama, yeniden boyutlandırılabilir bir pencerede olabilir. Katlanabilir cihazlarda olduğu gibi birden fazla fiziksel ekran bile olabilir. Bu durumların hiçbirinde, fiziksel ekran boyutu içeriğin nasıl gösterileceğine karar vermede önemli değildir.

Bunun yerine, ekranın uygulamanıza ayrılan gerçek bölümüne göre karar vermelisiniz (ör. Jetpack WindowManager kitaplığı tarafından sağlanan mevcut pencere metrikleri). WindowManager'ın Compose uygulamasında nasıl kullanıldığını görmek için JetNews örneğine göz atın.

Bu yaklaşımı benimsemek, uygulamanızın yukarıdaki tüm senaryolarda iyi davranacağı için daha esnek olmasını sağlar. Ayrıca, kullanıcıların kullanabileceği ekran alanına göre uyumlu hale getirdiğiniz düzenler, ChromeOS gibi platformları ve tabletler ile katlanabilir cihazlar gibi form faktörlerini desteklemek için gereken özel işlem miktarını azaltır.

Uygulamanız için kullanılabilen ilgili alanı gözlemledikten sonra, Pencere boyutu sınıflarını kullanma bölümünde açıklandığı gibi ham boyutu anlamlı bir boyut sınıfına dönüştürmek faydalı olur. Bu işlem, boyutları standart boyut gruplarına ayırır. Bu gruplar, uygulamanızı çoğu benzersiz durum için optimize etme esnekliğiyle basitliği dengelemek üzere tasarlanmış kesme noktalarıdır. Bu boyut sınıfları, uygulamanızın genel penceresini ifade eder. Bu nedenle, genel ekran düzeninizi etkileyen düzen kararları için bu sınıfları kullanın. Bu boyut sınıflarını durum olarak iletebilir veya iç içe yerleştirilmiş kompozisyonlara iletilecek türetilmiş durum oluşturmak için ek mantık yürütebilirsiniz.

@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ızda senkronize tutulması gereken birçok yere dağıtmak yerine tek bir konuma sınırlandırır. Bu tek konum, diğer tüm uygulama durumlarında olduğu gibi diğer derlenebilir öğelere açıkça aktarılabilen bir durum oluşturur. Durumu açıkça iletmek, tekil birleştirilebilirleri basitleştirir. Çünkü bunlar, boyut sınıfını veya belirtilen yapılandırmayı diğer verilerle birlikte alan normal birleştirilebilir işlevler olacaktır.

Esnek iç içe yerleştirilmiş kompozisyonlar yeniden kullanılabilir

Birleştirilebilirler, çeşitli yerlere yerleştirilebildiğinde daha fazla yeniden kullanılabilir. Bir bileşiğin her zaman belirli bir boyuta sahip olarak belirli bir yere yerleştirileceği varsayılırsa bu bileşiği başka bir yerde, farklı bir boyuta sahip olarak veya farklı bir alanda yeniden kullanmak daha zor olur. Bu, tek tek yeniden kullanılabilir bileşenlerin "genel" boyut bilgilerine dolaylı olarak bağımlı olmaktan kaçınması gerektiği anlamına da gelir.

Aşağıdaki örneği düşünün: Yan yana bir veya iki bölme gösterebilen liste-ayrıntı düzenini uygulayan iç içe yerleştirilmiş bir kompozisyon düşünün.

Yan yana iki bölmeyi gösteren bir uygulamanın ekran görüntüsü.
Şekil 2. Tipik bir liste-ayrıntı düzenini gösteren bir uygulamanın ekran görüntüsü. 1, liste alanı; 2, ayrıntı alanıdır.

Bu kararın uygulamanın genel düzeninin bir parçası olmasını istediğimizden, kararı yukarıda gördüğümüz gibi ekran düzeyinde bir bileşenden iletiriz:

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

Bunun yerine, bir bileşenin düzenini mevcut alana göre bağımsız olarak değiştirmesini istesek ne olur? Örneğin, alan izin veriyorsa ek ayrıntılar göstermek isteyen bir kart. Mevcut bir boyuta göre bazı mantık işlemleri yapmak istiyoruz ancak hangi boyuta göre?

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

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

Kompozit, ekran düzeyinde bir kompozit olmadığından yeniden kullanılabilirliği en üst düzeye çıkarmak için mevcut pencere metriklerini de doğrudan kullanmamalıyız. Bileşen, dolguyla yerleştiriliyorsa (ör. içe yerleştirilenler için) veya gezinme çubuğu ya da uygulama çubuğu gibi bileşenler varsa bileşenin kullanabileceği alan miktarı, uygulamanın kullanabileceği toplam alandan önemli ölçüde farklı olabilir.

Bu nedenle, derlenebilir öğenin kendisini oluşturmak için aslında verilen 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 istiyorsanız düzeni duyarlı hale getirmek için bir değiştirici koleksiyonu veya özel düzen kullanabilirsiniz. Bu, bazı çocukların mevcut alanı doldurması veya yeterli alan varsa çocukları birden fazla sütunda düzenlemek kadar basit olabilir.

Gösterdiğiniz öğeleri değiştirmek istiyorsanız daha güçlü bir alternatif olarak BoxWithConstraints öğesini kullanabilirsiniz. Bu derlenebilir, mevcut alana göre farklı derlenebilirleri çağırmak için kullanabileceğiniz ölçü kısıtlamaları sağlar. Ancak BoxWithConstraints, bu kısıtlamaların bilindiği düzen aşamasına kadar kompozisyonu ertelediğinden ve düzen sırasında daha fazla çalışma yapılmasına neden olduğundan bu işlem bazı maliyetlere neden olur.

@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 ekranda kullanıcıya küçük ekrana kıyasla daha fazla içerik gösterebilirsiniz. Bu davranışa sahip bir bileşeni uygularken verimli olmak ve verileri mevcut boyutun yan etkisi olarak yüklemek cazip gelebilir.

Ancak bu, verilerin uygun şekilde oluşturulması için toplanarak bileşenlere sağlanabileceği tek yönlü veri akışı ilkelerine aykırıdır. Verilerin bir kısmı her zaman kullanılmasa bile, birleştirilebilir öğenin her zaman herhangi bir boyutta görüntülemek için ihtiyaç duyduğu verilere sahip olması amacıyla birleştirilebilir öğeye yeterli 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ğini temel alarak, description değerinin her zaman Card değerine iletildiğini unutmayın. description yalnızca genişlik gösterilmesine izin verdiğinde kullanılsa da Card, mevcut genişlikten bağımsız olarak her zaman gereklidir.

Verileri her zaman iletmek, durum bilgisini azaltarak uyarlanabilir düzenleri basitleştirir ve boyutlar arasında geçiş yaparken yan etkilerin tetiklenmesini önler (pencerenin yeniden boyutlandırılması, yönü değiştirilmesi veya cihazın katlanması ve açılması nedeniyle ortaya çıkabilir).

Bu ilke, durum bilgilerinin düzen değişikliklerinde korunmasına da olanak tanır. Tüm boyutlarda kullanılamayabilecek bilgileri kaldırarak, sayfa düzeni boyutu değiştikçe kullanıcının durumunu koruyabiliriz. Örneğin, yeniden boyutlandırmalar nedeniyle düzenin açıklamayı gizleme ve gösterme arasında geçiş yapması durumunda kullanıcının durumunun korunması için bir showMore Boole işareti gönderebiliriz:

@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

Oluştur'daki özel düzenler hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara göz atın.

Örnek uygulamalar

  • CanonicalLayouts, büyük ekranlı cihazlarda optimum kullanıcı deneyimi sunan kanıtlanmış tasarım kalıplarının bulunduğu bir depodur.
  • JetNews, kullanıcı arayüzünü mevcut alandan yararlanacak şekilde uyarlayan bir uygulamanın nasıl tasarlanacağını gösterir
  • Yanıtla, mobil cihazları, tabletleri ve katlanabilir cihazları desteklemek için uyarlanabilir bir örnektir.
  • Android'de, farklı ekran boyutlarını desteklemek için uyarlanabilir düzenler kullanan bir uygulamadır.

Videolar