Uygulamanızda içeriği uçtan uca görüntüleyin ve Compose'da pencere eklerini tutun

Android platformu, durum çubuğu ve gezinme çubuğu gibi sistem kullanıcı arayüzünü çizmekten sorumludur. Bu sistem kullanıcı arayüzü, kullanıyor.

WindowInsets, uygulamanızın doğru alanda çizilmesini ve kullanıcı arayüzünüzün sistem kullanıcı arayüzü tarafından gizlenmemesini sağlamak için sistem kullanıcı arayüzü hakkında bilgi sağlar.

Sistem çubuklarının arkasından çizim yapmak için baştan sona gitme
Şekil 1. Sistem çubuklarının arkasından çizim yapmak için baştan sona gitme.

Android 14 (API düzeyi 34) ve önceki sürümlerde uygulamanızın kullanıcı arayüzü varsayılan olarak sistem çubukları ve ekran kesimleri vardır.

Android 15 (API düzeyi 35) ve sonraki sürümlerde, uygulamanız SDK 35'i hedefledikten sonra sistem çubuklarının altında çizim yapar ve ekranda kesitler gösterir. Bu, daha sorunsuz bir kullanıcı deneyimi sağlar ve uygulamanızın kendisine sunulan pencere alanından tam olarak yararlanmasına olanak tanır.

İçeriğin sistem kullanıcı arayüzünün arkasında gösterilmesine uçtan uca geçiş denir. Bu sayfada, farklı içe yerleştirilmiş içerik türleri, ekranı kenarlara kadar kullanma ve kullanıcı arayüzünüzü animasyonlu hale getirmek ve uygulamanızın içeriğinin sistem kullanıcı arayüzü öğeleriyle gizlenmemesini sağlamak için içe yerleştirilmiş içerik API'lerini kullanma hakkında bilgi edineceksiniz.

Ek temel bilgiler

Bir uygulamanın ekranı kenarlara kadar uzandığında, önemli içeriklerin ve etkileşimlerin sistem kullanıcı arayüzü tarafından gizlenmediğinden emin olmanız gerekir. Örneğin, bir düğme gezinme çubuğunun arkasına yerleştirilirse kullanıcı düğmeyi tıklayamayabilir.

Sistem kullanıcı arayüzünün boyutu ve yerleştirildiği yerle ilgili bilgiler eklemeler aracılığıyla belirtilir.

Sistem kullanıcı arayüzünün her bir bölümü, ve nereye yerleştirildiğini gösterir. Örneğin, durum çubuğu ekleri ve konum çubuğunun konumunu gösterirken, gezinme çubuğu ekleri gezinme çubuğunun boyutuna ve konumuna göre değişiyor. Her bir ek türü dört öğeden oluşur. piksel boyutları vardır: üst, sol, sağ ve alt. Bu boyutlar, sistem kullanıcı arayüzü, uygulama penceresinin ilgili taraflarından itibaren uzanır. Kaçınılması gerekenler Bu nedenle, uygulamanın kullanıcı arayüzü tutar.

Aşağıdaki yerleşik Android ek türleri WindowInsets aracılığıyla kullanılabilir:

WindowInsets.statusBars

Durum çubuklarını açıklayan ek açıklamalar. Bunlar, bildirim simgelerini ve diğer göstergeleri içeren üst sistem kullanıcı arayüzü çubuklarıdır.

WindowInsets.statusBarsIgnoringVisibility

Görünür oldukları zamanları durum çubuğu ekler. Durum çubukları şu anda gizliyse (tam ekran moduna girildiği için) ana durum çubuğu iç içe yerleştirilmeleri boş olur ancak bu iç içe yerleştirilmeler boş olmaz.

WindowInsets.navigationBars

Gezinme çubuklarını açıklayan ekler. Bunlar, cihazın sol, sağ veya alt tarafında bulunan ve görev çubuğunu ya da gezinme simgelerini açıklayan sistem kullanıcı arayüzü çubuklarıdır. Bu ayarlar, kullanıcının tercih ettiği gezinme yöntemine ve görev çubuğuyla etkileşimde bulunmasına bağlı olarak çalışma zamanında değişebilir.

WindowInsets.navigationBarsIgnoringVisibility

Görünür olduklarında gezinme çubuğu içe yerleştirilir. Gezinme çubukları şu anda gizliyse (kapsamlı tam ekran moduna geçilmesi nedeniyle) ana gezinme çubuğu ekleri boş olur, ancak bu ekler boş olmaz.

WindowInsets.captionBar

Üst başlık çubuğu gibi serbest biçimli bir pencerede sistem kullanıcı arayüzü pencere süslemesini açıklayan ek.

WindowInsets.captionBarIgnoringVisibility

Altyazı çubuğu, ne zaman görünür olacağına eklenir. Altyazı çubukları şu anda gizliyse ana altyazı çubuğu iç içe yerleştirilmeleri boş olur ancak bu iç içe yerleştirilmeler boş olmaz.

WindowInsets.systemBars

Durum çubukları, gezinme çubukları ve altyazı çubuğunu içeren sistem çubuğu iç içe yerleştirilmelerinin birleşimi.

WindowInsets.systemBarsIgnoringVisibility

Görünür oldukları zamanlara ilişkin sistem çubuğu ekler. Sistem çubukları şu anda gizliyse (kapsamlı tam ekran moduna geçilmesi nedeniyle) ana sistem çubuğu ekleri boş olur, ancak bu ekler boş olmaz.

WindowInsets.ime

Yazılım klavyenin alt kısımda kapladığı alanı açıklayan iç içe yerleştirilmiş resimler.

WindowInsets.imeAnimationSource

Yazılım klavyesinin, geçerli klavye animasyonundan önce kapladığı alan miktarını açıklayan ekler.

WindowInsets.imeAnimationTarget

Yazılım klavyenin mevcut klavye animasyonundan sonra kaplayacak alan miktarını açıklayan iç içe yerleştirilmiş resimler.

WindowInsets.tappableElement

Gezinme kullanıcı arayüzü hakkında daha ayrıntılı bilgi veren ve "dokunduğunda" dokunma işlemlerinin uygulama tarafından değil sistem tarafından işleneceği alan miktarını gösteren bir tür içe yerleştirilmiş öğe. Hareketle gezinme içeren şeffaf gezinme çubuklarında, bazı uygulama öğeleri sistem gezinme kullanıcı arayüzü üzerinden dokunulabilir.

WindowInsets.tappableElementIgnoringVisibility

Dokunulabilir öğe, görünür oldukları zamanlara eklenir. Dokunulabilir öğeler şu anda gizliyse (etkileyici tam ekran moduna girmesi nedeniyle) dokunulabilir ana öğe ek ayarları boş olur ancak bu ek öğeler boş olmaz.

WindowInsets.systemGestures

Sistemin gezinme hareketlerine müdahale edeceği eklerin miktarını temsil eden ekler. Uygulamalar, Modifier.systemGestureExclusion aracılığıyla bu hareketlerin sınırlı bir kısmının işlenmesini manuel olarak belirtebilir.

WindowInsets.mandatorySystemGestures

Sistem tarafından her zaman işlenecek ve Modifier.systemGestureExclusion üzerinden devre dışı bırakılamayan sistem hareketlerinin bir alt kümesi.

WindowInsets.displayCutout

Ekran kesiğiyle (çentik veya delik) çakışmamayı önlemek için gereken boşluk miktarını gösteren iç içe yerleştirilmiş resimler.

WindowInsets.waterfall

Şelale görüntüsünün kavisli alanlarını temsil eden ek kısımlar. Şelale ekranda, ekranın cihazın yanlarına doğru kıvrıldığı, ekranın kenarlarında kavisli alanlar bulunur.

Bu türlerin özeti, içeriğin gizlenmemesini sağlayan üç "güvenli" içe yerleştirilme türüne göre yapılır:

Bunlar "güvenli" inset türleri, içerik türüne bağlı olarak içeriği farklı şekillerde korur. temel platform eklerini inceleyin:

  • Çizmemesi gereken içerikleri korumak için WindowInsets.safeDrawing özelliğini kullanın herhangi bir sistem arayüzünün altında. Eklerin en yaygın şekilde kullanıldığı durumlar şunlardır: sistem kullanıcı arayüzü tarafından (kısmen veya .
  • Hareketlerle içerikleri korumak için WindowInsets.safeGestures özelliğini kullanın. Bu sayede sistem hareketleri, uygulama hareketleriyle (alt sayfalar, bantlar veya oyunlardaki hareketler gibi) çakışmaz.
  • İçeriğin görsel ve hareketsel olarak örtüşmediğinden emin olmak için WindowInsets.safeDrawing ve WindowInsets.safeGestures ile birlikte WindowInsets.safeContent öğesini kullanın.

Insets kurulumu

Uygulamanızın içerik çektiği yerler üzerinde tam kontrol sahibi olmak için şu ayarları uygulayın: adımları. Bu adımlar olmadan, uygulamanız yazılım klavyesiyle eş zamanlı olarak animasyon uygulamamalıdır.

  1. Android 15 ve sonraki sürümlerde uçtan uca ekranı zorunlu kılmak için SDK 35 veya sonraki sürümleri hedefleyin. Uygulamanız, sistem kullanıcı arayüzünün arkasında gösterilir. Uygulamanızın kullanıcı arayüzünü, ek'ler.
  2. İsteğe bağlı olarak, şu numarayı çağırın: enableEdgeToEdge() Activity.onCreate(), önceki deneyimde uygulamanızın baştan sona Android sürümleri.
  3. Etkinliğinizde android:windowSoftInputMode="adjustResize" AndroidManifest.xml giriş. Bu ayar, uygulamanızın yazılım IME'sinin boyutunu içe yerleştirilmiş olarak almasına olanak tanır. Bu boyutu, IME uygulamanızda göründüğünde ve kaybolduğunda içeriği uygun şekilde doldurmak ve düzenlemek için kullanabilirsiniz.

    <!-- 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">
    

API oluşturma

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 ayrıca uygulamanızın düzenini inset değişiklikleri.

Örneğin bu, ekleri içeriğe uygulamanın en temel yöntemidir. kullanın:

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. Google Etiket Yöneticisi'nin sonra, eklerin uygulandığı yerlerde tek tek ekranda ince ayar yapmanız gerekir veya bileşen bazında sunmanızı sağlar.

Bu içe yerleştirilen türlerin tümü, API 21'e geri bağlanan IME animasyonlarıyla otomatik olarak animasyonlu hale getirilir. Dolayısıyla, bu ekleri kullanan tüm düzenleriniz Ayrıca, inset değerleri değiştikçe otomatik olarak canlandırılır.

Oluşturulabilir reklam öğenizi ayarlamak için bu ek türlerini kullanmanın iki temel yolu vardır düzenler: dolgu değiştiricileri ve iç içe yerleştirilmiş boyut değiştiricileri

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) geçerlidir güvenli çizim, 4 tarafın hepsinde dolgu olarak yer alır.

En yaygın ek türleri için çeşitli yerleşik yardımcı program yöntemleri de vardır. Modifier.safeDrawingPadding(), eşdeğeri olan yöntemlerden biridir. Modifier.windowInsetsPadding(WindowInsets.safeDrawing). RACI matrisinde değiştiricileri belirleyin.

Inset boyut değiştiricileri

Aşağıdaki değiştiriciler, bileşenin inset boyutu olması gerekir:

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)

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

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

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

Bu değiştiriciler özellikleSpacer inset alanı:

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

Inset tüketimi

İç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ç dolgu değiştiricileri ve iç dolgu boyutu değiştiricileri, kompozisyon ağacında daha derine inerken iç dolguların bir kısmının dış iç dolgu değiştiriciler tarafından zaten kullanıldığını bilir ve iç dolguların aynı kısmını birden fazla kez kullanmaktan kaçınır. Bu da çok fazla ek alan kullanılmasına neden olur.

Inset boyut değiştiricileri, eklerin aynı bölümünü birden fazla kez kullanmaktan da kaçınır . Ancak, kurumsal sorumluluklarını değiştirdikleri için, boyutunu doğrudan kullanmazlar.

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

Önceki LazyColumn örneğine baktığımızda LazyColumn, imePadding değiştiricisiyle yeniden boyutlandırıldı. 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 kapatıldığında imePadding() değiştiricisi dolgu uygulamaz çünkü IME'nin yüksekliği yoktur. imePadding() değiştiricisi hiçbir dolgu uygulamadığından, iç içe yerleştirilmiş öğ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 dolgu uygulamaya başladığında, bu miktarda içe yerleştirilmiş öğe de tüketilmeye başlar. Bu nedenle, sistem çubuklarının aralığı imePadding() değiştiricisi tarafından zaten uygulandığından 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 kapatıldığında değişiklikler tersten gerçekleşir: Spacer imePadding(), Spacer işareti, yüksekliğin yüksekliğine eşitlenene kadar, sistem çubuklarının alt tarafındaki devre dışı bırakıldıktan sonra sistem çubuklarının alt tarafındaki

Ş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ç başka şekilde de etkilenebilir.

Modifier.consumeWindowInsets(insets: WindowInsets) ek öğeleri de tüketir Modifier.windowInsetsPadding ile aynıdır ancak bu tür dolgu olarak tüketilir. 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) çok davranıyor WindowInsets bağımsız değişkeni olan sürüme benzer, ancak isteğe bağlı PaddingValues. 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. Bununla birlikte, aşağıdaki uyarılardan dolayı, pencere iç içe geçmiş dolgusunu kullanmayı tercih edin değiştiricileri ve pencere içleri boyut değiştiricileri kullanın.

İç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 sayesinde eklerin Jetpack'in evreleriyle özel bir ilişkisi vardır Oluştur'u tıklayın.

İç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. Yerleşik değiştiricileri, her bir özelliğin değerini kullanarak bu sayfada emin olun. Bu şekilde, içe aktarılan değerlerin aynı kareyi seçmeniz gerekir.

WindowInsets ile klavye IME animasyonlarını kullanma

Kaydırma içeren bir kapsayıcıya Modifier.imeNestedScroll() uygulayarak kapsayıcının alt kısmına kaydırdığınızda IME'yi otomatik olarak açıp kapatabilirsiniz.

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

        WindowCompat.setDecorFitsSystemWindows(window, false)

        setContent {
            MaterialTheme {
                MyScreen()
            }
        }
    }
}

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun MyScreen() {
    Box {
        LazyColumn(
            modifier = Modifier
                .fillMaxSize() // fill the entire window
                .imePadding() // padding for the bottom for the IME
                .imeNestedScroll(), // scroll IME at the bottom
            content = { }
        )
        FloatingActionButton(
            modifier = Modifier
                .align(Alignment.BottomEnd)
                .padding(16.dp) // normal 16dp of padding for FABs
                .navigationBarsPadding() // padding for navigation bar
                .imePadding(), // padding for when IME appears
            onClick = { }
        ) {
            Icon(imageVector = Icons.Filled.Add, contentDescription = "Add")
        }
    }
}

Klavye yer açmak için yukarı ve aşağı kaydırılan kullanıcı arayüzü öğesini gösteren animasyon
Şekil 3. IME animasyonları.

Material 3 Bileşenleri için inset desteği

Kullanım kolaylığı açısından, yerleşik Material 3 composable'larının çoğu (androidx.compose.material3) composable'ların uygulamanıza nasıl yerleştirildiklerine bağlı olarak eklerin kendilerini işlemesi Malzeme spesifikasyonlarına uygun olmalıdır.

Inset işleme composable'ları

Aşağıda Malzeme listesi verilmiştir bileşenlerden inset'leri otomatik olarak işler.

Uygulama çubukları

İçerik kapsayıcıları

İskele

Varsayılan olarak Scaffold kullanmanız ve kullanmanız için paddingValues parametresi olarak ek değerler sağlar. Scaffold, içeriklere içe yerleştirilen öğeleri uygulamaz. Bu sorumluluk size aittir. Örneğin, bu ek öğeleri Scaffold içinde bir LazyColumn ile kullanmak için:

Scaffold { innerPadding ->
    // innerPadding contains inset information for you to use and apply
    LazyColumn(
        // consume insets as scaffold doesn't do it by default
        modifier = Modifier.consumeWindowInsets(innerPadding),
        contentPadding = innerPadding
    ) {
        items(count = 100) {
            Box(
                Modifier
                    .fillMaxWidth()
                    .height(50.dp)
                    .background(colors[it % colors.size])
            )
        }
    }
}

Varsayılan ek değerlerini geçersiz kıl

composable'a iletilen windowInsets parametresini şu şekilde değiştirebilirsiniz: composable'ın davranışını yapılandırın. Bu parametre, bunun yerine uygulanacak farklı bir pencere içe yerleştirilmesi türü olabilir veya boş bir örnek geçirilerek devre dışı bırakılabilir: WindowInsets(0, 0, 0, 0).

Örneğin, LargeTopAppBar, windowInsets parametresini boş bir örneğe ayarlayın:

LargeTopAppBar(
    windowInsets = WindowInsets(0, 0, 0, 0),
    title = {
        Text("Hi")
    }
)

Görüntüleme sistemi iç içe yerleştirilmiş içerikleriyle birlikte çalışabilirlik

Ekranınızda aynı hiyerarşide hem Görünümler hem de Oluştur kodu varsa varsayılan iç içe eklemeleri geçersiz kılmanız gerekebilir. Bu durumda, konu hakkında ek öğeleri hangisinin tüketmesi gerektiği ve hangisinin yoksayılması gerektiği.

Örneğin, en dıştaki düzeniniz bir Android View düzeniyse insetleri Görüntüle sisteminde tüketme ve Oluşturma için bunları yoksayma. Alternatif olarak, en dıştaki düzeniniz bir bileşense Oluştur'da iç içe eklemeleri kullanmanız ve AndroidView bileşenlerini uygun şekilde doldurmanız gerekir.

Varsayılan olarak her ComposeView, tüm içe yerleştirilen öğeleri WindowInsetsCompat tüketim düzeyinde tüketir. Bu varsayılan davranışı değiştirmek için ComposeView.consumeWindowInsets değerini false olarak ayarlayın.

Kaynaklar