mediaQuery ile uyarlanabilir düzenler için sorgu bilgileri

Uygulama düzeninizi güncellemek için cihaz özelliği ve uygulama durumu gibi çeşitli bilgilere ihtiyacınız vardır. Pencere genişliği ve yüksekliği en çok tercih edilen bilgilerdir. Buna ek olarak, aşağıdaki bilgilere de göz atabilirsiniz:

  • Pencere duruşu
  • İşaretleme cihazlarının hassasiyeti
  • Klavye türü
  • Kamera ve mikrofonun cihaz tarafından desteklenip desteklenmediği
  • Kullanıcı ile cihaz ekranı arasındaki mesafe

Bilgiler dinamik olarak güncellendiğinden, bilgileri izlemeniz ve herhangi bir güncelleme olduğunda yeniden oluşturmayı tetiklemeniz gerekir. mediaQuery işlevi, bilgiyi getirmeyle ilgili ayrıntıları soyutlaştırır ve düzen güncellemelerini tetikleyecek koşulu tanımlamaya odaklanmanızı sağlar. Aşağıdaki örnekte, katlanabilir cihaz masa üstü duruşundayken düzen TabletopLayout olarak değiştiriliyor:

@Composable
fun VideoPlayer(
    // ...
) {
    // ...
            if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) {
                TabletopLayout()
            } else {
                FlatLayout()
            }
    // ...
}

mediaQuery işlevini etkinleştirme

mediaQuery işlevini etkinleştirmek için ComposeUiFlags nesnesinin isMediaQueryIntegrationEnabled özelliğini true olarak ayarlayın:

class MyApplication : Application() {
    override fun onCreate() {
        ComposeUiFlags.isMediaQueryIntegrationEnabled = true
        super.onCreate()
    }
}

Parametrelerle koşul tanımlama

Bir koşulu, UiMediaScope içinde değerlendirilen bir lambda olarak tanımlayabilirsiniz. mediaQuery işlevi, koşulu mevcut duruma ve cihaz özelliklerine göre değerlendirir. İşlev bir Boole değeri döndürür. Bu nedenle, if ifadesi gibi koşullu dallarla düzeni belirleyebilirsiniz. Tablo 1'de UiMediaScope içinde kullanılabilen parametreler açıklanmaktadır.

Parametre Değer türü Açıklama
windowWidth Dp Geçerli pencere genişliği (dp).
windowHeight Dp Geçerli pencere yüksekliği (dp cinsinden).
windowPosture UiMediaScope.Posture Uygulama penceresinin mevcut duruşu.
pointerPrecision UiMediaScope.PointerPrecision Mevcut işaretleme cihazlarının en yüksek hassasiyeti.
keyboardKind UiMediaScope.KeyboardKind Kullanılabilir veya bağlı klavye türü.
hasCamera Boolean Kameranın cihazda desteklenip desteklenmediği.
hasMicrophone Boolean Mikrofonun cihazda desteklenip desteklenmediği.
viewingDistance UiMediaScope.ViewingDistance Kullanıcı ile cihaz ekranı arasındaki tipik mesafe.

UiMediaScope nesnesi, parametrelerin değerlerini çözer. mediaQuery işlevi, mevcut cihaz özelliklerini ve bağlamını temsil eden UiMediaScope nesnesine erişmek için LocalUiMediaScope.current kullanır. Bu nesne, kullanıcı cihazın duruşunu değiştirdiğinde olduğu gibi herhangi bir değişiklik yapıldığında dinamik olarak güncellenir. mediaQuery işlevi daha sonra güncellenen UiMediaScope nesnesiyle query lambda'sını değerlendirir ve bir Boole değeri döndürür. Örneğin, aşağıdaki snippet, windowPosture parametre değerine göre TabletopLayout ve FlatLayout arasında seçim yapar.

@Composable
fun VideoPlayer(
    // ...
) {
    // ...
            if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) {
                TabletopLayout()
            } else {
                FlatLayout()
            }
    // ...
}

Pencere boyutuna göre karar verme

Pencere boyutu sınıfları, duyarlı düzenler tasarlamanıza, geliştirmenize ve test etmenize yardımcı olan bir dizi görüntü alanı kesme noktasıdır. Geçerli pencere boyutunu temsil eden iki parametreyi, pencere boyutu sınıflarında tanımlanan eşikle karşılaştırabilirsiniz. Aşağıdaki örnekte, bölme sayısı pencere genişliğine göre değiştiriliyor. WindowSizeClass sınıfında, pencere boyutu sınıflarının eşikleri için sabitler bulunur (Şekil 1).

derivedMediaQuery işlevi, query lambda'sını değerlendirir ve sonucu derivedStateOf içine sarar. windowWidth ve windowHeight parametreleri sık sık güncellenebileceğinden, query lambda'sında bu parametrelere başvururken mediaQuery işlevi yerine derivedMediaQuery işlevini çağırın.

val narrowerThanMedium by derivedMediaQuery {
    windowWidth < WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND.dp
}
val narrowerThanExpanded by derivedMediaQuery {
    windowWidth < WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND.dp
}
when {
    narrowerThanMedium -> SinglePaneLayout()
    narrowerThanExpanded -> TwoPaneLayout()
    else -> ThreePaneLayout()
}

Şekil 1. Düzen, pencere genişliğine göre güncellenir.

Düzeni pencere duruşuna göre güncelleme

windowPosture parametresi, mevcut pencere duruşunu UiMediaScope.Posture nesnesi olarak tanımlar. Parametreyi UiMediaScope.Posture sınıfında tanımlanan değerlerle karşılaştırarak mevcut posture değerini kontrol edebilirsiniz. Aşağıdaki örnekte, düzen pencere duruşuna göre değiştirilir:

when {
    mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout()
    mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout()
    mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout()
}

Mevcut işaretleme cihazının hassasiyetini kontrol etme

Yüksek hassasiyetli bir işaretleme cihazı, kullanıcıların bir kullanıcı arayüzü öğesini tam olarak işaretlemesine yardımcı olur. İşaretleme cihazının hassasiyeti, cihaz türüne bağlıdır.

pointerPrecision parametresi, fare ve dokunmatik ekran gibi kullanılabilir işaretleme cihazlarının hassasiyetini açıklar. UiMediaScope.PointerPrecision sınıfında tanımlanmış dört değer vardır: Fine, Coarse, Blunt ve None. None, işaretleme cihazının kullanılamadığı anlamına gelir. Hassasiyet, en yüksekten en düşüğe doğru şu sırayla değişir: Fine, Coarse ve Blunt.

Birden fazla işaretleme cihazı varsa ve bunların hassasiyetleri farklıysa parametre en yüksek hassasiyetle çözülür. Örneğin, iki işaretleme cihazı varsa (Fine hassasiyet cihazı ve Blunt hassasiyet cihazı) Fine, pointerPrecision parametresinin değeridir.

Aşağıdaki örnekte, kullanıcı düşük hassasiyetli bir işaretleme cihazı kullanırken daha büyük bir düğme gösterilmektedir:

if (mediaQuery { pointerPrecision == UiMediaScope.PointerPrecision.Blunt }) {
    LargeSizeButton()
} else {
    NormalSizeButton()
}

Kullanılabilir klavye türünü kontrol etme

keyboardKind parametresi, kullanılabilir klavyelerin türünü gösterir: Physical, Virtual ve None. Dokunmatik klavye gösteriliyorsa ve aynı anda donanım klavyesi de kullanılabiliyorsa parametre Physical olarak çözümlenir. İkisi de algılanmazsa parametrenin değeri None olur. Aşağıdaki örnekte, klavye algılanmadığında kullanıcılara klavye bağlamalarını öneren bir mesaj gösterilmektedir:

if (mediaQuery { keyboardKind == UiMediaScope.KeyboardKind.None }) {
    SuggestKeyboardConnect()
}

Cihazın kamera ve mikrofonu destekleyip desteklemediğini kontrol edin.

Bazı cihazlar kamera veya mikrofonu desteklemez. hasCamera ve hasMicrophone parametreleriyle cihazın kamera ve mikrofonu destekleyip desteklemediğini kontrol edebilirsiniz. Aşağıdaki örnekte, cihaz desteklediğinde kamera ve mikrofonla kullanılacak düğmeler gösterilmektedir:

Row {
    OutlinedTextField(state = rememberTextFieldState())
    // Show the MicButton when the device supports a microphone.
    if (mediaQuery { hasMicrophone }) {
        MicButton()
    }
    // Show the CameraButton when the device supports a camera.
    if (mediaQuery { hasCamera }) {
        CameraButton()
    }
}

Kullanıcı arayüzünü tahmini izleme mesafesine göre ayarlama

İzleme mesafesi, düzeni belirlemeye yardımcı olan bir faktördür. Kullanıcı uygulamayı uzaktan kullanıyorsa metinlerin ve kullanıcı arayüzü öğelerinin daha büyük olmasını bekler. viewingDistance parametresi, cihaz türüne ve tipik kullanım bağlamına göre görüntüleme mesafesi tahmini sağlar.

UiMediaScope.ViewingDistance sınıfında tanımlanan üç değer vardır: Near, Medium ve Far. Near, ekranın yakın mesafede olduğunu, Far ise cihazın uzaktan görüntülendiğini gösterir. Aşağıdaki örnekte, görüntüleme mesafesi Far veya Medium olduğunda yazı tipi boyutu artırılır:

val fontSize = when {
    mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Far } -> 20.sp
    mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Medium } -> 18.sp
    else -> 16.sp
}

Kullanıcı arayüzü bileşenini önizleme

UI bileşenlerini önizlemek için composable işlevlerde mediaQuery ve derivedMediaQuery işlevlerini çağırabilirsiniz. Aşağıdaki snippet, windowPosture parametre değerine göre TabletopLayout ve FlatLayout arasında seçim yapar. TabletopLayout önizlemek için windowPosture parametresi UiMediaScope.Posture.Tabletop olmalıdır.

when {
    mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout()
    mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout()
    mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout()
}

mediaQuery ve derivedMediaQuery işlevleri, LocalUiMediaScope.current olarak sağlanan bir UiMediaScope nesnesi içinde verilen query lambda'yı değerlendirir. Aşağıdaki adımları uygulayarak bu ayarı geçersiz kılabilirsiniz:

  1. mediaQuery işlevini etkinleştirin.
  2. UiMediaScope arayüzünü uygulayan özel bir nesne tanımlayın.
  3. CompositionLocalProvider işleviyle özel nesneyi LocalUiMediaScope olarak ayarlayın.
  4. CompositionLocalProvider işlevinin içerik lambda'sında önizlemek için composable'ı çağırın.

Aşağıdaki örnekle TabletopLayout önizlemesini yapabilirsiniz:

@Preview
@Composable
fun PreviewLayoutForTabletop() {
    // Step 1: Enable the mediaQuery function
    ComposeUiFlags.isMediaQueryIntegrationEnabled = true

    val currentUiMediaScope = LocalUiMediaScope.current
    // Step 2: Define a custom object implementing the UiMediaScope interface.
    // The object overrides the windowPosture parameter.
    // The resolution of the remaining parameters is deferred to the currentUiMediaScope object.
    val uiMediaScope = remember(currentUiMediaScope) {
        object : UiMediaScope by currentUiMediaScope {
            override val windowPosture: UiMediaScope.Posture = UiMediaScope.Posture.Tabletop
        }
    }

    // Step 3: Set the object to the LocalUiMediaScope.
    CompositionLocalProvider(LocalUiMediaScope provides uiMediaScope) {
        // Step 4: Call the composable to preview.
        when {
            mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout()
            mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout()
            mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout()
        }
    }
}