Uyarlanabilir düzenler oluşturma

Uygulamanızın kullanıcı arayüzü farklı ekran boyutları, yönler ve form faktörlerine yanıt verecek şekilde uyumlu olmalıdır. Uyarlanabilir düzen, kullanılabilir ekran alanına göre değişir. Bu değişiklikler arasında basit düzen düzenlemelerinden alan doldurmaya ve ek alandan yararlanmak için düzenleri tamamen değiştirmeye kadar değişiklik gösterebilir.

Bildirim temelli bir kullanıcı arayüzü araç seti olan Jetpack Compose, içeriği çeşitli boyutlarda farklı şekilde oluşturmak için kendilerini ayarlayan düzenler tasarlamak ve uygulamak için çok uygundur. Bu dokümanda, kullanıcı arayüzünüzü duyarlı hale getirmek için Oluşturma'yı nasıl kullanacağınızla ilgili bazı yönergeler bulunmaktadır.

Ekran düzeyinde oluşturulan besteler için büyük düzen değişikliklerini açık hale getirin

Bir uygulamanın tamamını yerleştirmek için Compose'u kullanırken, uygulamanızın oluşturulması için izin verilen tüm alanı uygulama düzeyinde ve ekran düzeyinde besteler 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. Sabit bir somut değeri temel alarak (cihaz bir tablet mi) karar vermek cazip gelebilir. Fiziksel ekranın belirli bir en boy oranı var mı?), ancak bu soruların yanıtları, kullanıcı arayüzünüzün birlikte ç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 diyagram

Tabletlerde bir uygulama çoklu pencere modunda çalışıyor olabilir. Diğer bir deyişle, uygulama ekranı başka bir uygulamaya bölüyor olabilir. ChromeOS'te bir uygulama, yeniden boyutlandırılabilir bir pencerede olabilir. Hatta katlanabilir cihaz gibi birden fazla fiziksel ekran olabilir. Bu durumların tümünde, fiziksel ekran boyutu içeriğin nasıl gösterileceğ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 vermelisiniz. Bir Compose uygulamasında WindowManager'ı nasıl kullanacağınızı görmek için JetNews örneğine göz atın.

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

Uygulamanız için mevcut olan ilgili alanı gözlemledikten sonra, Pencere Boyutu Sınıfları bölümünde açıklandığı gibi ham boyutu anlamlı bir boyut sınıfına dönüştürmek faydalı olacaktır. Bu işlem, boyutları standart boyut grupları halinde gruplandırır. Bunlar, uygulamanızı en benzersiz durumlar için optimize etme esnekliğiyle sadeliği dengelemek için tasarlanmış ayrılma noktalarıdır. Bu boyut sınıfları, uygulamanızın genel aralığını belirtir. 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 aktarabilir veya iç içe yerleştirilmiş composable öğelere aktarmak üzere türetilmiş durum oluşturmak için ek mantık gerçekleştirebilirsiniz.

class MainActivity : ComponentActivity() {
    @OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            val windowSizeClass = calculateWindowSizeClass(this)
            MyApp(windowSizeClass)
        }
    }
}
@Composable
fun MyApp(windowSizeClass: WindowSizeClass) {
    // Perform logic on the size class to decide whether to show
    // the top app bar.
    val showTopAppBar = windowSizeClass.heightSizeClass != 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ırlandırır. Bu tek konum, durum bilgisini oluşturur. Bu durum, diğer uygulama durumlarında olduğu gibi, diğer bestecilere açıkça aktarılabilir. Durumu açık bir şekilde geçirmek, diğer verilerle birlikte boyut sınıfını veya belirtilen yapılandırmayı alan normal kompozit işlevler olacakları için bağımsız kompozisyonları basitleştirir.

İç içe yerleştirilmiş esnek kompozitler yeniden kullanılabilir.

Çok çeşitli yerlere yerleştirilebilen besteler daha çok yeniden kullanılabilir hâle gelir. Oluşturulan bir dosyanın her zaman belirli bir boyutla belirli bir konuma yerleştirileceği varsayılırsa, başka bir yerde veya farklı miktarda kullanılabilir alanla başka bir yerde yeniden kullanılması daha zor olur. Bu aynı zamanda, tek tek, yeniden kullanılabilir bestelerin "global" boyut bilgilerine bağlı olarak dolaylı yoldan kaçınılması gerektiği anlamına da gelir.

Bir örneği inceleyelim: Yan yana bir veya iki bölme gösterebilen list-detail düzeni uygulayan iç içe yerleştirilmiş bir beste düşünün.

Yan yana iki bölmeyi gösteren bir uygulama ekran görüntüsü

1. Şekil. Tipik bir liste/ayrıntı düzenini gösteren bir uygulamanın ekran görüntüsü. 1 liste alanını, 2 ise ayrıntı alanını ifade eder.

Bu kararın, uygulamanın genel düzeninin bir parçası olmasını istiyoruz. Bu yüzden, kararı, yukarıda gördüğümüz gibi ekran düzeyinde bir oluşturma etkinliğinden aşağı aktarırız:

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

Bunun yerine bir bestenin düzenini mevcut alana göre bağımsız olarak değiştirmesini istersek ne olur? Örneğin, alan izin vermesi durumunda ek ayrıntıları göstermek isteyen bir kart. Mevcut bir boyuta göre bazı mantık gerçekleştirmek istiyoruz ama özellikle hangi boyuta göre hareket etmek istiyoruz?

İki farklı kart örneği: Yalnızca bir simge ve başlığı gösteren dar bir kart ve 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ının boyutunu kullanmaktan kaçınmalıyız. Bu hata birden fazla ekran için doğru olmaz ve uygulama tam ekran değilse doğru olmaz.

Oluşturulan dosya ekran düzeyinde kompozisyona sahip 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 dolgu ile yerleştiriliyorsa (ör. iç içe yerleştirilmiş öğeler için) ya da gezinme rayları ya da uygulama çubukları gibi bileşenler varsa oluşturulabilir içerik için kullanılabilecek alan, uygulamanın genel alanından önemli ölçüde farklı olabilir.

Dolayısıyla, composable'ın gerçekten kendisini oluşturmak için verildiği genişliği kullanmamız gerekir. Bu genişliği elde etmek için iki seçeneğimiz vardır:

İçeriğin nerede veya nasıl gösterileceğini değiştirmek istiyorsanız düzeni duyarlı hale getirmek için bir değiştiriciler koleksiyonu veya özel düzen kullanabilirsiniz. Bunu, bir çocuğun mevcut tüm alanı doldurmasını sağlamak veya yeterli alan varsa çocukları birden çok sütuna gelecek şekilde yerleştirmek kadar basit bir şey olabilir.

Gösterdiğiniz içeriği değiştirmek istiyorsanız, daha güçlü bir alternatif olarak BoxWithConstraints kullanabilirsiniz. Bu beste, kullanılabilir alana göre farklı besteleme öğeleri çağırmak için kullanabileceğiniz ölçüm kısıtlamaları sağlar. Ancak BoxWithConstraints, bu kısıtlamaların bilindiği Düzen aşamasına kadar kompozisyonu ertelediğinden, yerleşim sırasında daha fazla iş yapılmasına neden olur. Bu nedenle bu işlemin maliyetli olması gerekir.

@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östermek için alanınız olabilir. Bu davranışa sahip bir oluşturma işlemi uygulanırken verimli olmak ve verileri mevcut boyutun bir yan etkisi olarak yüklemek cazip gelebilir.

Ancak bu, verilerin uygun şekilde oluşturulması için kaldırılıp basit bir şekilde birleştirilebilir öğelere sağlandığı tek yönlü veri akışı ilkelerine aykırıdır. Oluşturulabilir öğeye yeterli miktarda veri sağlanmalıdır. Böylece, verilerin bir kısmı her zaman kullanılmasa bile, beste öğesinin her zaman tüm boyutlarda görüntülemek gerekenlere sahip olması sağlanı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şliğin gösterilmesine izin verdiğinde kullanılsa da Card, kullanılabilir genişlik ne olursa olsun her zaman bunu gerektirir.

Verilerin her zaman geçirilmesi, uyarlanabilir düzenleri daha az durum bilgili hale getirerek daha basit hale getirir ve boyutlar arasında geçiş yaparken (bu durum pencere yeniden boyutlandırması, yön değişikliği veya cihazın katlanıp genişletilmesi nedeniyle ortaya çıkabilir) yan etkileri önler.

Bu ilke, aynı zamanda düzen değişiklikleri genelinde durumun korunmasına da izin verir. 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şareti 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

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

Örnek uygulamalar

  • Büyük ekran standart düzenleri, büyük ekranlı cihazlarda optimum kullanıcı deneyimi sağlayan başarısı kanıtlanmış tasarım kalıplarının yer aldığı bir depodur.
  • JetNews, kullanıcı arayüzünü mevcut alanı kullanacak şekilde uyarlayan bir uygulamanın nasıl tasarlanacağını gösteriyor
  • Yanıt mobil cihazları, tabletleri ve katlanabilir cihazları desteklemek için uyarlanabilir bir örnektir
  • Artık Android'de farklı ekran boyutlarını desteklemek için uyarlanabilir düzenler kullanan bir uygulamadır.

Videolar