Masaüstü pencerelerini destekleme

Pencereli görüntüleme, kullanıcıların yeniden boyutlandırılabilir uygulama pencerelerinde aynı anda birden fazla uygulama çalıştırmasına olanak tanıyarak çok yönlü, masaüstüne benzer bir deneyim sunar.

Şekil 1'de, pencereli görüntüleme etkinleştirilmiş ekranın düzenini görebilirsiniz. Önemli noktalar:

  • Kullanıcılar birden fazla uygulamayı aynı anda yan yana çalıştırabilir.
  • Görev çubuğu, ekranın alt kısmında sabit bir konumda bulunur ve çalışan uygulamaları gösterir. Kullanıcılar, hızlı erişim için uygulamaları sabitleyebilir.
  • Yeni özelleştirilebilir başlık çubuğu, her pencerenin üst kısmını simge durumuna küçültme ve ekranı kaplama gibi kontrollerle süsler.
Şekil 1. Tablette pencereli görüntüleme.

Uygulamalar, Android tabletlerde varsayılan olarak tam ekran açılır. Bir uygulamayı pencereli görüntüleme modunda başlatmak için ekranın üst kısmındaki pencere tutma yerine basılı tutun ve tutma yerini kullanıcı arayüzünde sürükleyin (Şekil 2'de gösterildiği gibi).

Bir uygulama pencereli görüntüleme modunda açıldığında diğer uygulamalar da masaüstü pencerelerinde açılır.

Şekil 2. Pencereli görüntülemeye girmek için uygulama penceresinin tutma yerine basılı tutup sürükleyin.

Kullanıcılar, pencere tutma yerine dokunduklarında veya tıkladıklarında ya da Meta tuşu (Windows, Komut veya Arama) + Ctrl + Aşağı klavye kısayolunu kullandıklarında pencere tutma yerinin altında gösterilen menüden de pencereli görüntülemeyi etkinleştirebilir.

Kullanıcılar, tüm etkin pencereleri kapatarak veya masaüstü penceresinin üst kısmındaki pencere tutma yerini tutup uygulamayı ekranın üst kısmına sürükleyerek pencereli görüntülemeden çıkabilir. Meta + H klavye kısayolu da pencereli görüntülemeden çıkıp uygulamaları tekrar tam ekranda çalıştırır.

Masaüstü pencereli görüntüleme özelliğine dönmek için Son Kullanılanlar ekranında masaüstü alanı kartına dokunun veya kartı tıklayın.

Uygulama düzeninizi masaüstü benzeri bir ortam için optimize etme

Masaüstü deneyimi için tasarım yapmak, daha geniş ekran alanı, fare ve klavye girişinin hassasiyeti ve yüksek üretkenlik beklentisi nedeniyle mobil tasarımdan önemli ölçüde farklı olabilir.

Jetpack WindowManager, geliştiricilerin masaüstü kullanıcı arayüzünü ne zaman göstereceklerine karar vermelerine yardımcı olan, fikir sahibi bir API sağlar. Masaüstü kullanıcı arayüzü genellikle daha yüksek bilgi yoğunluğuna, farklı gezinme kalıplarına ve optimize edilmiş fare etkileşimlerine sahiptir.

lifecycleScope.launch(Dispatchers.Main) {
    lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
        windowInfoTracker.windowEngagementInfo(this@DesktopWindowingActivity)
            .collect { windowEngagementInfo ->
                if(windowEngagementInfo.hasEngagementMode(WindowEngagementInfo.EngagementMode.PRECISE_POINTER)){
                    showDesktopOptimizedUI()
                }else {
                    showTouchOptimizedUI()
                }
        }
    }
}

Daha fazla bilgi edinmek için Masaüstü için tasarım başlıklı makaleyi inceleyin.

Yeniden boyutlandırılabilirlik ve uyumluluk modu

Pencereli görüntüleme modunda, yönü kilitli uygulamalar serbestçe yeniden boyutlandırılabilir. Bu, bir etkinlik dikey yöne kilitli olsa bile kullanıcıların uygulamayı yatay yönlü bir pencereye yeniden boyutlandırabileceği anlamına gelir.

Şekil 3. Dikey kısıtlamalı bir uygulamanın penceresini yatay olarak yeniden boyutlandırma.

Yeniden boyutlandırılamaz olarak tanımlanan uygulamaların (yani resizeableActivity = false) kullanıcı arayüzü, aynı en boy oranı korunarak ölçeklendirilir.

Şekil 4. Yeniden boyutlandırılamayan bir uygulamanın kullanıcı arayüzü, pencere yeniden boyutlandırıldıkça ölçeklenir.

Yönü kilitleyen veya yeniden boyutlandırılamaz olarak tanımlanan kamera uygulamalarının kamera vizörleri için özel bir işlem uygulanır: Pencere tamamen yeniden boyutlandırılabilir ancak vizör aynı en-boy oranını korur. Uygulamaların her zaman dikey veya yatay modda çalıştığı varsayıldığında, uygulamalar önizlemenin veya çekilen görüntünün yönünün ya da en boy oranının yanlış hesaplanmasına yol açan varsayımlarda bulunur. Bu da görüntülerin gerilmesine, yan veya baş aşağı görünmesine neden olur.

Uygulamalar tamamen duyarlı kamera vizörleri uygulamaya hazır olana kadar özel işlem, yanlış varsayımların neden olabileceği etkileri azaltan daha temel bir kullanıcı deneyimi sunar.

Kamera uygulamaları için uyumluluk modu hakkında daha fazla bilgi edinmek isterseniz Cihaz uyumluluğu modu başlıklı makaleyi inceleyin.

Şekil 5. Kamera vizörü, pencere yeniden boyutlandırıldığında en boy oranını korur.

Özelleştirilebilir başlık ekleri

Pencereli görüntüleme modunda çalışan tüm uygulamalarda, yoğun içerik modunda bile başlık çubuğu bulunur. Uygulamanızın içeriğinin gizlenmesini önlemek ve özel kullanıcı arayüzü öğelerini doğrudan başlık alanına çizmek için bu çubuğu özelleştirebilirsiniz.

Özel üstbilgiler uygulanmadan önce ve sonra Chrome.
Şekil 6. Özel üstbilgiler uygulanmadan önce ve sonra Chrome.

Uygulama

Başlık çubuğuna özel içerik çizmek için ilk adım, başlık çubuğu arka planını şeffaf hale getirmektir. Bunu yapmak için WindowInsetsController ile APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND işaretini kullanabilirsiniz.

window.insetsController?.setSystemBarsAppearance(
    WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND,
    WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND
)

Üstbilgi çubuğu şeffaf hale geldikten sonra üstbilgi alanını uygulamanızın tasarımına uyacak şekilde şekillendirebilirsiniz. Çubuğun mevcut olup olmadığını tespit etmek ve düzeninize uygun yüksekliği veya dolguyu uygulamak için WindowInsets.isCaptionBarVisible kullanın.

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun CaptionBar() {
    if (WindowInsets.isCaptionBarVisible) {
        Row(
            modifier = Modifier
                .windowInsetsTopHeight(WindowInsets.captionBar)
                .fillMaxWidth()
                .background(if (isSystemInDarkTheme()) Color.White else Color.Black),
            horizontalArrangement = Arrangement.Center,
            verticalAlignment = Alignment.CenterVertically
        ) {
            Text(
                text = "Caption Bar Title",
                style = MaterialTheme.typography.titleMedium,
                modifier = Modifier.padding(4.dp)
            )
        }
    }
}

  • setSystemBarsAppearance(appearance,mask): Sistem çubuklarının görsel stilini yapılandırır. İlk parametre, hedef görünüm işaretlerini tanımlarken ikinci parametre, hangi işaretlerin değiştirileceğini kontrol eden bir maske görevi görür.

  • windowInsetsTopHeight(): Composable'ınızın yüksekliğini sistemin başlık çubuğuyla eşleşecek şekilde otomatik olarak ayarlar. Böylece özel arka planınız, piksel değerlerini sabit kodlamadan altyazı alanını doldurur.

  • WindowInsets.captionBar: Masaüstü pencereli görüntüleme kontrollerinin (Kapat, Ekranı kapla vb.) boyutlarını sağlar. Böylece kullanıcı arayüzünüz, masaüstü pencereli görüntüleme moduna girerken veya bu moddan çıkarken otomatik olarak ölçeklendirilir ya da gizlenir.

Daha fazla bilgi için Pencere iç metinleri hakkında bölümüne bakın. Başlık çubuğunda başlığın yanı sıra Google Chrome'daki gibi sekmeler, arama çubukları veya profil avatarları gibi diğer kullanıcı arayüzü öğelerini de gösterebilirsiniz.

Kullanıcı arayüzü

Android 15, kullanıcı arayüzünüzün sistem düğmeleriyle çakışmasını önlemek için WindowInsets#getBoundingRects() yöntemini sunar. Yöntem, sistem öğelerinin kapladığı alanları temsil eden Rect nesnelerinin listesini döndürür. Başlık çubuğunda kalan alan, özel içerikleri güvenle yerleştirebileceğiniz güvenli bölgedir.

APPEARANCE_LIGHT_CAPTION_BARS kısayolunu kullanarak açık ve koyu temalar için sistem altyazısı öğelerinin görünümünü değiştirin. İç kısımlara erişmek için Compose'da WindowInsets.Companion.captionBar(), Görünümler'de ise WindowInsets.Type.captionBar() kullanın.

Daha fazla bilgi için Pencere iç metinleri hakkında bölümüne bakın.

Çoklu görev ve aynı anda çalışan birden çok kopya desteği

Çoklu görev, pencereli görüntülemenin temelini oluşturur ve uygulamanızın birden fazla örneğine izin vermek, kullanıcıların üretkenliğini büyük ölçüde artırabilir.

Android 15'ten itibaren PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI kullanabilirsiniz. AndroidManifest.xml uygulamanızda bu özelliği ayarlayarak sistem kullanıcı arayüzünün, uygulamanın birden fazla örnekte başlatılması için seçenekler ("Yeni Pencere" düğmesi gibi) sunması gerektiğini belirtirsiniz.

<application>
    <property
        android:name="android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI"
        android:value="true" />
</application>

Not: Masaüstü pencereli görüntüleme ve diğer çok pencereli ortamlarda yeni görevler yeni bir pencerede açılır. Bu nedenle, uygulamanız birden fazla görev başlattığında kullanıcı yolculuğunu tekrar kontrol edin.

Uygulama örneklerini sürükleme hareketleriyle yönetme

Çoklu pencere modunda kullanıcılar, bir kullanıcı arayüzü öğesini (ör. sekme veya doküman) uygulama penceresinin dışına sürükleyerek yeni bir uygulama örneği başlatabilir. Kullanıcılar, aynı uygulamanın farklı örnekleri arasında da öğe taşıyabilir.

Şekil 7. Bir sekmeyi pencereli görüntüleme penceresinin dışına sürükleyerek yeni bir Chrome örneği başlatın.

Sürükle ve bırak yöntemiyle veri aktarma

Kullanıcıların içeriği uygulamanızın başka bir örneğine sürüklemesine veya içeriği ekranın boş bir alanına bırakarak yeni bir örnek oluşturmasına olanak tanıyan aynı anda çalışan birden çok kopya sürükle ve bırak işlemi için bir composable'ı sürükleme kaynağı olarak yapılandırmak üzere dragAndDropSource değiştiricisini kullanın. Lambda'sında, aktarılacak verileri içeren ClipData ve aynı anda çalışan birden çok kopya davranışını yapılandırmak için işaretleri ileterek DragAndDropTransferData değerini döndürün.

Android 15, masaüstü tarzı pencereleme ve aynı anda çalışan birden çok kopya etkileşimleri için iki önemli işaret sunar:

  • DRAG_FLAG_GLOBAL_SAME_APPLICATION: Sürükleme işleminin pencere sınırlarını aşabileceğini gösterir (aynı uygulamanın birden fazla örneği için). startDragAndDrop() bu işaret ayarlanmış olarak çağrıldığında yalnızca aynı uygulamaya ait görünür pencereler sürükleme işlemine katılabilir ve sürüklenen içeriği alabilir.

Modifier.dragAndDropSource { _ ->
    DragAndDropTransferData(
        clipData = ClipData.newPlainText("label", "Your data"),
        flags = View.DRAG_FLAG_GLOBAL_SAME_APPLICATION
    )
}

Modifier.dragAndDropSource { _ ->
    val intent = Intent.makeMainActivity(activity.componentName).apply {
        putExtra("EXTRA_ITEM_ID", itemId)
        flags = Intent.FLAG_ACTIVITY_NEW_TASK or
                Intent.FLAG_ACTIVITY_MULTIPLE_TASK or
                Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT
    }

    val pendingIntent = PendingIntent.getActivity(
        activity, 0, intent, PendingIntent.FLAG_IMMUTABLE
    )

    val data = ClipData(
        "Item $itemId",
        arrayOf(ClipDescription.MIMETYPE_TEXT_INTENT),
        ClipData.Item.Builder().setIntentSender(pendingIntent.intentSender).build()
    )

    DragAndDropTransferData(
        clipData = data,
        flags = View.DRAG_FLAG_GLOBAL_SAME_APPLICATION or
                View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
    )
}

Aktarılan verileri alma

Başka bir örnekten veri kabul etmek için dragAndDropTarget değiştiricisini kullanın. Veriler farklı bir örnekten veya uygulamadan geliyorsa izinleri açıkça istemeniz gerekir.

Modifier.dragAndDropTarget(
    shouldStartDragAndDrop = { event ->
        event.toAndroidDragEvent().clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)
    },
    target = object : DragAndDropTarget {
        override fun onDrop(event: DragAndDropEvent): Boolean {
            requestDragAndDropPermissions(activity, event.toAndroidDragEvent())
            val clipData = event.toAndroidDragEvent().clipData
            val item = clipData?.getItemAt(0)?.text
            if (item != null) {
                // Process the dropped text item here
            }
            return item != null
        }
    }
)

Temel adımlar:

  • Filtre: Gelen verilerin (MIME türü) desteklenip desteklenmediğini kontrol etmek için shouldStartDragAndDrop kullanın.
  • İzinler: Verilere erişmek için requestDragAndDropPermissions(event) yöntemini çağırın.
  • İşleme: onDrop geri çağırmasındaki verileri ayıklayın.

Ek optimizasyonlar

Uygulama başlatma işlemlerini özelleştirme ve uygulamaları pencereli görüntülemeden tam ekrana geçirme

Varsayılan boyutu ve konumu belirtme

Yeniden boyutlandırılabilir olsa bile tüm uygulamaların kullanıcıya değer sunmak için büyük bir pencereye ihtiyacı yoktur. Bir etkinlik başlatıldığında varsayılan boyut ve konum belirtmek için ActivityOptions#setLaunchBounds() yöntemini kullanabilirsiniz.

Masaüstü alanından tam ekrana geçme

Uygulamalar, Activity#requestFullScreenMode() yöntemini çağırarak tam ekrana geçebilir. Bu yöntem, uygulamayı doğrudan pencereli görüntüleme modundan tam ekran olarak gösterir.