Pencere içe eklemelerini ayarlama

Uygulamanızın, içerikleri nereden alacağı konusunda tam kontrol sahibi olmasını sağlamak için aşağıdaki kurulum adımlarını uygulayın. Bu adımlar uygulanmazsa uygulamanız, sistem kullanıcı arayüzünün arkasında siyah veya düz renkler çizebilir ya da yazılım klavyesiyle senkronize olarak animasyon oluşturmayabilir.

  1. Android 15 ve sonraki sürümlerde kenardan kenara ekranı zorunlu kılmak için Android 15 (API düzeyi 35) veya sonraki sürümleri hedefleyin. Uygulamanız, sistem kullanıcı arayüzünün arkasında gösterilir. İçeriği çerçeve içine alarak uygulamanızın kullanıcı arayüzünü ayarlayabilirsiniz.
  2. İsteğe bağlı olarak, Activity.onCreate() içinde enableEdgeToEdge()'i çağırabilirsiniz. Bu, uygulamanızın önceki Android sürümlerinde uçtan uca ekran kullanmasına olanak tanır.
  3. Etkinliğinizin AndroidManifest.xml girişinde android:windowSoftInputMode="adjustResize" değerini ayarlayın. Bu ayar, uygulamanızın yazılım IME'sinin boyutunu iç içe yerleştirilmiş olarak almasına olanak tanır. Bu sayede, IME uygulamanızda göründüğünde ve kaybolduğunda uygun düzeni ve dolguyu uygulamanız kolaylaşır.

    <!-- In your AndroidManifest.xml file: -->
    <activity
      android:name=".ui.MainActivity"
      android:label="@string/app_name"
      android:windowSoftInputMode="adjustResize"
      android:theme="@style/Theme.MyApplication"
      android:exported="true">
    

Compose API'lerini kullanma

Etkinliğiniz tüm içe yerleştirilen öğelerin işlenmesini kontrol altına aldıktan sonra, içeriğin gizlenmediğinden ve etkileşimli öğelerin sistem kullanıcı arayüzüyle örtüşmediğinden emin olmak için Compose API'lerini kullanabilirsiniz. Bu API'ler, uygulamanızın düzenini de içe yerleştirilen değişikliklerle senkronize eder.

Örneğin, uygulamanızın tamamının içeriğine içe yerleştirilmiş öğeleri uygulamanın en temel yöntemi şudur:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    enableEdgeToEdge()

    setContent {
        Box(Modifier.safeDrawingPadding()) {
            // the rest of the app
        }
    }
}

Bu snippet, safeDrawing pencere içe eklemelerini uygulamanın tüm içeriğinin etrafına dolgu olarak uygular. Bu, etkileşimli öğelerin sistem kullanıcı arayüzüyle örtüşmemesini sağlarken uygulamanın hiçbirinin kenardan kenara efekt elde etmek için sistem kullanıcı arayüzünün arkasında çizilmeyeceği anlamına da gelir. Pencerenin tamamını kullanmak için ekranlara veya bileşenlere göre içe yerleştirilen öğelerin uygulandığı yerlerde ince ayar yapmanız gerekir.

Bu içe yerleştirilen türlerin tümü, API 21'e geri bağlanan IME animasyonlarıyla otomatik olarak animasyonlu hale getirilir. Ayrıca, bu iç içe yerleştirilen öğeleri kullanan tüm düzenleriniz, iç içe yerleştirilen öğe değerleri değiştikçe otomatik olarak animasyonlu hale gelir.

Composable düzenlerinizi ayarlamak için bu içe yerleştirilmiş türleri kullanmanın iki temel yolu vardır: dolgu değiştiriciler ve içe yerleştirilmiş boyut değiştiriciler.

Dolgu değiştiriciler

Modifier.windowInsetsPadding(windowInsets: WindowInsets), belirtilen pencere içe eklemelerini tıpkı Modifier.padding gibi dolgu olarak uygular. Örneğin, Modifier.windowInsetsPadding(WindowInsets.safeDrawing) güvenli çizim iç içe eklemelerini 4 tarafın tamamına dolgu olarak uygular.

Ayrıca, en yaygın içe yerleştirilmiş metin türleri için çeşitli yerleşik yardımcı program yöntemleri de vardır. Modifier.safeDrawingPadding(), Modifier.windowInsetsPadding(WindowInsets.safeDrawing) ile eşdeğer olan bu yöntemlerden biridir. Diğer içe yerleştirilmiş türlerde de benzer değiştiriciler vardır.

İçerik ekleme boyutu değiştiricileri

Aşağıdaki değiştiriciler, bileşenin boyutunu iç içe yerleştirilen öğelerin boyutuna ayarlayarak bir miktar pencere iç içe yerleştirilen öğesi uygular:

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

windowInsets öğesinin başlangıç tarafını genişlik olarak uygular (Modifier.width gibi)

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

windowInsets öğesinin son tarafını genişlik olarak uygular (Modifier.width gibi)

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

windowInsets öğesinin üst tarafını yükseklik olarak uygular (Modifier.height gibi)

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

windowInsets öğesinin alt tarafını yükseklik olarak uygular (Modifier.height gibi)

Bu değiştiriciler, özellikle de iç içe yerleştirilmiş öğelerin alanını kaplayan bir Spacer öğesinin boyutunu belirlemek için yararlıdır:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

İçe doğru tüketim

İçe yerleştirilen dolgu değiştiricileri (windowInsetsPadding ve safeDrawingPadding gibi yardımcılar), içe yerleştirilenlerin dolgu olarak uygulanan kısmını otomatik olarak tüketir. İç içe yerleştirilmiş iç içe ekleme dolgu değiştiricileri ve iç içe ekleme boyutu değiştiricileri, kompozisyon ağacında daha derine inerken iç içe eklemelerin bir kısmının dış iç içe ekleme dolgu değiştiricileri tarafından zaten kullanıldığını bilir ve iç içe eklemelerin aynı kısmını birden fazla kez kullanmaktan kaçınır. Bu da çok fazla ek alan kullanılmasına neden olur.

İçeriği ekleme boyutu değiştiriciler, eklentiler zaten kullanılmışsa eklentilerin aynı kısmının birden fazla kez kullanılmasını da önler. Ancak boyutlarını doğrudan değiştirdikleri için kendileri yerleşik reklam tüketmez.

Sonuç olarak, iç içe yerleştirilmiş dolgu değiştiriciler her bir kompozisyona uygulanan dolgu miktarını otomatik olarak değiştirir.

Önceki LazyColumn örneğine baktığımızda, LazyColumn, imePadding değiştiricisi tarafından yeniden boyutlandırılıyor. LazyColumn içinde, son öğe sistem çubuklarının alt kısmının yüksekliğine göre boyutlandırılır:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

IME kapalıyken imePadding() değiştirici, IME'nin yüksekliği olmadığı için dolgu uygulamaz. imePadding() değiştiricisi hiçbir dolgu uygulamadığından, içe yerleştirilen öğe kullanılmaz ve Spacer öğesinin yüksekliği, sistem çubuklarının alt tarafının boyutu olur.

IME açıldığında IME içe yerleştirilenleri, IME'nin boyutuna uyacak şekilde animasyonlu olarak ayarlanır ve imePadding() değiştirici, IME açıldığında LazyColumn öğesini yeniden boyutlandırmak için alt dolgu uygulamaya başlar. imePadding() değiştirici alt dolguyu uygulamaya başladığında, bu miktarda içe yerleştirilmiş öğeyi de tüketmeye başlar. Bu nedenle, sistem çubuklarının aralığı imePadding() değiştiricisi tarafından uygulanmış olduğundan Spacer öğesinin yüksekliği azalmaya başlar. imePadding() değiştirici, sistem çubuklarından daha büyük bir alt dolgu miktarı uyguladığında Spacer öğesinin yüksekliği sıfır olur.

IME kapandığında değişiklikler ters yönde gerçekleşir: imePadding(), sistem çubuklarının alt tarafından daha az uygulandığında Spacer sıfır yükseklikten genişlemeye başlar. IME tamamen animasyonla kapatıldığında Spacer, sistem çubuklarının alt tarafının yüksekliğiyle eşleşir.

Şekil 2. TextField ile kenardan kenara üşengeç sütun.

Bu davranış, tüm windowInsetsPadding değiştiriciler arasında iletişim kurularak gerçekleştirilir ve birkaç farklı şekilde etkilenebilir.

Modifier.consumeWindowInsets(insets: WindowInsets), Modifier.windowInsetsPadding ile aynı şekilde içe yerleştirilen öğeleri tüketir ancak tüketilen içe yerleştirilen öğeleri dolgu olarak uygulamaz. Bu, belirli miktarda iç içe yerleştirilmiş öğenin zaten kullanıldığını kardeş öğelere belirtmek için iç içe yerleştirilmiş öğe boyutu değiştiricileriyle birlikte kullanışlıdır:

Column(Modifier.verticalScroll(rememberScrollState())) {
    Spacer(Modifier.windowInsetsTopHeight(WindowInsets.systemBars))

    Column(
        Modifier.consumeWindowInsets(
            WindowInsets.systemBars.only(WindowInsetsSides.Vertical)
        )
    ) {
        // content
        Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
    }

    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
}

Modifier.consumeWindowInsets(paddingValues: PaddingValues), WindowInsets bağımsız değişkeni olan sürüme çok benzer şekilde çalışır ancak rastgele bir PaddingValues alır. Bu, dolgu veya aralığın, iç dolgu değiştiricilerden başka bir mekanizma (ör. normal Modifier.padding veya sabit yükseklikli aralıklar) tarafından sağlandığında çocukları bilgilendirmek için kullanışlıdır:

Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) {
    // content
    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
}

Ham pencere içe eklemelerinin tüketim olmadan gerekli olduğu durumlarda doğrudan WindowInsets değerlerini kullanın veya tüketimden etkilenmeyen içe eklemelerin PaddingValues değerini döndürmek için WindowInsets.asPaddingValues() kullanın. Ancak aşağıdaki uyarılar nedeniyle, mümkün olduğunda pencere içe ekleme dolgu değiştiricilerini ve pencere içe ekleme boyutu değiştiricilerini kullanmayı tercih edin.

İçerikler ve Jetpack Compose aşamaları

Compose, iç içe yerleştirilen öğeleri güncellemek ve animasyonlu hale getirmek için temel AndroidX çekirdek API'lerini kullanır. Bu API'ler, iç içe yerleştirilen öğeleri yöneten temel platform API'lerini kullanır. Bu platform davranışı nedeniyle, içe yerleştirilenler Jetpack Compose aşamalarıyla özel bir ilişkiye sahiptir.

İçe yerleştirilenlerin değeri, kompozisyon aşamasından sonra ancak düzen aşamasından önce güncellenir. Bu, kompozisyondaki içe yerleştirilen öğelerin değerinin okunması için genellikle bir kare gecikmeli bir içe yerleştirilen öğe değeri kullanılacağı anlamına gelir. Bu sayfada açıklanan yerleşik değiştiriciler, iç içe yerleştirilen öğelerin değerlerinin yerleşim aşamasına kadar kullanılmasının geciktirilmesi için tasarlanmıştır. Bu sayede, iç içe yerleştirilen öğe değerleri güncellendikleri karede kullanılır.