Uygulamanızın kullanıma sunulmasını sağlayın

Katlanmış durumdayken büyük ekranlar ve benzersiz katlanmış durumlar, katlanabilir cihazlarda yeni kullanıcı deneyimleri sağlar. Uygulamanızı katlanabilir cihazlara uygun hale getirmek için katlar ve menteşeler gibi katlanabilir cihaz penceresi özellikleri için API yüzeyi sağlayan Jetpack WindowManager kitaplığını kullanın. Uygulamanız katlanabilir cihazlara uyumlu olduğunda, önemli içerikleri katlama veya menteşe alanına yerleştirmemek için düzenini uyarlayabilir ve katlama ile menteşeleri doğal ayırıcılar olarak kullanabilir.

Bir cihazın masaüstü veya kitap duruşu gibi yapılandırmaları destekleyip desteklemediğini anlamak, farklı düzenleri destekleme veya belirli özellikler sunma ile ilgili kararlara rehberlik edebilir.

Pencere bilgileri

Jetpack WindowManager'daki WindowInfoTracker arayüzü, pencere düzeni bilgilerini gösterir. Arayüzün windowLayoutInfo() yöntemi, uygulamanızı katlanabilir cihazın katlanma durumu hakkında bilgilendiren bir WindowLayoutInfo veri akışı döndürür. WindowInfoTracker#getOrCreate() yöntemi, WindowInfoTracker örneği oluşturur.

WindowManager, Kotlin akışları ve Java geri çağırma işlevlerini kullanarak WindowLayoutInfo verilerini toplama desteği sağlar.

Kotlin akışları

WindowLayoutInfo veri toplamayı başlatmak ve durdurmak için, yaşam döngüsü en az STARTED olduğunda repeatOnLifecycle kod bloğunun yürütüldüğü ve yaşam döngüsü STOPPED olduğunda durdurulduğu bir yeniden başlatılabilir yaşam döngüsü bilinçli işleyici kullanabilirsiniz. Yaşam döngüsü tekrar STARTED olduğunda kod bloğunun yürütülmesi otomatik olarak yeniden başlatılır. Aşağıdaki örnekte, kod bloğu WindowLayoutInfo verilerini toplayıp kullanır:

class DisplayFeaturesActivity : AppCompatActivity() {

    private lateinit var binding: ActivityDisplayFeaturesBinding

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

        binding = ActivityDisplayFeaturesBinding.inflate(layoutInflater)
        setContentView(binding.root)

        lifecycleScope.launch(Dispatchers.Main) {
            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
                WindowInfoTracker.getOrCreate(this@DisplayFeaturesActivity)
                    .windowLayoutInfo(this@DisplayFeaturesActivity)
                    .collect { newLayoutInfo ->
                        // Use newLayoutInfo to update the layout.
                    }
            }
        }
    }
}

Java geri çağırmaları

androidx.window:window-java bağımlılığına dahil edilen geri çağırma uyumluluk katmanı, Kotlin akışı kullanmadan WindowLayoutInfo güncellemelerini toplamanıza olanak tanır. Yapı, WindowLayoutInfo güncellemelerini almak için geri çağırmaları kaydetmek (ve kayıtlarını iptal etmek) desteklemek üzere bir WindowInfoTracker uyarlayan WindowInfoTrackerCallbackAdapter sınıfını içerir. Örneğin:

public class SplitLayoutActivity extends AppCompatActivity {

    private WindowInfoTrackerCallbackAdapter windowInfoTracker;
    private ActivitySplitLayoutBinding binding;
    private final LayoutStateChangeCallback layoutStateChangeCallback =
            new LayoutStateChangeCallback();

   @Override
   protected void onCreate(@Nullable Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);

       binding = ActivitySplitLayoutBinding.inflate(getLayoutInflater());
       setContentView(binding.getRoot());

       windowInfoTracker =
                new WindowInfoTrackerCallbackAdapter(WindowInfoTracker.getOrCreate(this));
   }

   @Override
   protected void onStart() {
       super.onStart();
       windowInfoTracker.addWindowLayoutInfoListener(
                this, Runnable::run, layoutStateChangeCallback);
   }

   @Override
   protected void onStop() {
       super.onStop();
       windowInfoTracker
           .removeWindowLayoutInfoListener(layoutStateChangeCallback);
   }

   class LayoutStateChangeCallback implements Consumer<WindowLayoutInfo> {
       @Override
       public void accept(WindowLayoutInfo newLayoutInfo) {
           SplitLayoutActivity.this.runOnUiThread( () -> {
               // Use newLayoutInfo to update the layout.
           });
       }
   }
}

RxJava desteği

RxJava (2 veya 3 sürümü) kullanıyorsanız Kotlin akışı kullanmadan WindowLayoutInfo güncellemelerini toplamak için Observable veya Flowable kullanmanıza olanak tanıyan yapılardan yararlanabilirsiniz.

androidx.window:window-rxjava2 ve androidx.window:window-rxjava3 bağımlılıkları tarafından sağlanan uyumluluk katmanı, uygulamanızın WindowLayoutInfo güncellemeleri almasını sağlayan WindowInfoTracker#windowLayoutInfoFlowable() ve WindowInfoTracker#windowLayoutInfoObservable() yöntemlerini içerir. Örneğin:

class RxActivity: AppCompatActivity {

    private lateinit var binding: ActivityRxBinding

    private var disposable: Disposable? = null
    private lateinit var observable: Observable<WindowLayoutInfo>

   @Override
   protected void onCreate(@Nullable Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);

       binding = ActivitySplitLayoutBinding.inflate(getLayoutInflater());
       setContentView(binding.getRoot());

        // Create a new observable.
        observable = WindowInfoTracker.getOrCreate(this@RxActivity)
            .windowLayoutInfoObservable(this@RxActivity)
   }

   @Override
   protected void onStart() {
       super.onStart();

        // Subscribe to receive WindowLayoutInfo updates.
        disposable?.dispose()
        disposable = observable
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe { newLayoutInfo ->
            // Use newLayoutInfo to update the layout.
        }
   }

   @Override
   protected void onStop() {
       super.onStop();

        // Dispose of the WindowLayoutInfo observable.
        disposable?.dispose()
   }
}

Katlanabilir ekranların özellikleri

Jetpack WindowManager'ın WindowLayoutInfo sınıfı, görüntüleme penceresinin özelliklerini DisplayFeature öğelerinin listesi olarak sunar.

FoldingFeature, aşağıdakiler de dahil olmak üzere katlanabilir ekranlarla ilgili bilgi sağlayan bir DisplayFeature türüdür:

  • state: Cihazın katlanmış durumu (FLAT veya HALF_OPENED)

  • orientation: Katlama veya menteşenin yönü, HORIZONTAL veya VERTICAL

  • occlusionType: Kıvrımın veya menteşenin ekranın bir kısmını gizleyip kapatmayacağı, NONE veya FULL

  • isSeparating: Katlama veya menteşenin iki mantıksal görüntüleme alanı oluşturup oluşturmayacağı (doğru veya yanlış)

HALF_OPENED olan katlanabilir cihazlar, ekran iki ekran alanına ayrıldığı için isSeparating değerini her zaman doğru olarak bildirir. Ayrıca, uygulama her iki ekranı da kapladığında isSeparating çift ekranlı cihazlarda her zaman doğru olur.

FoldingFeature bounds özelliği (DisplayFeature kaynağından devralınır), katlama veya menteşe gibi katlama özelliğinin sınırlayıcı dikdörtgenini temsil eder. Sınırlar, ekrandaki öğeleri özelliğe göre konumlandırmak için kullanılabilir:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    lifecycleScope.launch(Dispatchers.Main) {
        lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
            // Safely collects from WindowInfoTracker when the lifecycle is
            // STARTED and stops collection when the lifecycle is STOPPED.
            WindowInfoTracker.getOrCreate(this@MainActivity)
                .windowLayoutInfo(this@MainActivity)
                .collect { layoutInfo ->
                    // New posture information.
                    val foldingFeature = layoutInfo.displayFeatures
                        .filterIsInstance<FoldingFeature>()
                        .firstOrNull()
                    // Use information from the foldingFeature object.
                }

        }
    }
}

Java

private WindowInfoTrackerCallbackAdapter windowInfoTracker;
private final LayoutStateChangeCallback layoutStateChangeCallback =
                new LayoutStateChangeCallback();

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    ...
    windowInfoTracker =
            new WindowInfoTrackerCallbackAdapter(WindowInfoTracker.getOrCreate(this));
}

@Override
protected void onStart() {
    super.onStart();
    windowInfoTracker.addWindowLayoutInfoListener(
            this, Runnable::run, layoutStateChangeCallback);
}

@Override
protected void onStop() {
    super.onStop();
    windowInfoTracker.removeWindowLayoutInfoListener(layoutStateChangeCallback);
}

class LayoutStateChangeCallback implements Consumer<WindowLayoutInfo> {
    @Override
    public void accept(WindowLayoutInfo newLayoutInfo) {
        // Use newLayoutInfo to update the Layout.
        List<DisplayFeature> displayFeatures = newLayoutInfo.getDisplayFeatures();
        for (DisplayFeature feature : displayFeatures) {
            if (feature instanceof FoldingFeature) {
                // Use information from the feature object.
            }
        }
    }
}

Masaüstü duruşu

FoldingFeature nesnesine dahil edilen bilgileri kullanarak uygulamanız, telefonun bir yüzeye yerleştirildiği, menteşenin yatay konumda olduğu ve katlanabilir ekranın yarı açık olduğu masaüstü gibi duruşları destekleyebilir.

Masaüstü duruşu, kullanıcılara telefonlarını ellerinde tutmadan kullanma kolaylığı sunar. Masaüstü duruşu, medya izlemek, fotoğraf çekmek ve görüntülü görüşme yapmak için idealdir.

Şekil 1. Masaüstü modunda bir video oynatıcı uygulaması.

Cihazın masaüstü modunda olup olmadığını belirlemek için FoldingFeature.State ve FoldingFeature.Orientation parametrelerini kullanın:

Kotlin

fun isTableTopPosture(foldFeature : FoldingFeature?) : Boolean {
    contract { returns(true) implies (foldFeature != null) }
    return foldFeature?.state == FoldingFeature.State.HALF_OPENED &&
            foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
}

Java

boolean isTableTopPosture(FoldingFeature foldFeature) {
    return (foldFeature != null) &&
           (foldFeature.getState() == FoldingFeature.State.HALF_OPENED) &&
           (foldFeature.getOrientation() == FoldingFeature.Orientation.HORIZONTAL);
}

Cihazın masaüstü modunda olduğunu öğrendikten sonra uygulama düzeninizi buna göre güncelleyin. Medya uygulamaları için bu, genellikle oynatma düğmesini ekranın üst kısmına yerleştirmek ve eller serbest izleme veya dinleme deneyimi için kontrolleri ve ek içeriği hemen altına yerleştirmek anlamına gelir.

Android 15 (API seviyesi 35) ve sonraki sürümlerde, cihazın mevcut durumundan bağımsız olarak bir cihazın masaüstü modunu destekleyip desteklemediğini algılamak için senkron API çağırabilirsiniz.

API, cihaz tarafından desteklenen duruşların listesini sağlar. Listede masa üstü duruşu varsa uygulama düzeninizi duruşu destekleyecek şekilde bölebilir, masaüstü ve tam ekran düzenler için uygulamanızın kullanıcı arayüzünde A/B testleri çalıştırabilirsiniz.

Kotlin

if (WindowSdkExtensions.getInstance().extensionsVersion >= 6) {
    val postures = WindowInfoTracker.getOrCreate(context).supportedPostures
    if (postures.contains(TABLE_TOP)) {
        // Device supports tabletop posture.
   }
}

Java

if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 6) {
    List<SupportedPosture> postures = WindowInfoTracker.getOrCreate(context).getSupportedPostures();
    if (postures.contains(SupportedPosture.TABLETOP)) {
        // Device supports tabletop posture.
    }
}

Örnekler

Kitap duruşu

Bir başka benzersiz katlanabilir özellik ise cihazın yarı açık, menteşesinin dikey olduğu kitap duruşudur. Kitap okuma duruşu, e-kitap okumak için idealdir. Katlanabilir büyük ekranda ciltli bir kitap gibi açılan iki sayfalık bir düzene sahip kitap modu, gerçek bir kitap okuma deneyimini yakalar.

Ellerinizi kullanmadan fotoğraf çekerken farklı bir en boy oranı kullanmak isterseniz de bu özelliği kullanabilirsiniz.

Kitap duruşunu, masaüstü duruşunda kullanılan tekniklerle uygulayın. Tek fark, kodun katlama özelliğinin yönü için yatay yerine dikey değeri kontrol etmesidir:

Kotlin

fun isBookPosture(foldFeature : FoldingFeature?) : Boolean {
    contract { returns(true) implies (foldFeature != null) }
    return foldFeature?.state == FoldingFeature.State.HALF_OPENED &&
            foldFeature.orientation == FoldingFeature.Orientation.VERTICAL
}

Java

boolean isBookPosture(FoldingFeature foldFeature) {
    return (foldFeature != null) &&
           (foldFeature.getState() == FoldingFeature.State.HALF_OPENED) &&
           (foldFeature.getOrientation() == FoldingFeature.Orientation.VERTICAL);
}

Pencere boyutu değişiklikleri

Bir uygulamanın görüntüleme alanı, cihaz yapılandırmasında yapılan bir değişiklik sonucunda değişebilir. Örneğin, cihaz katlandığında veya açıldığında, döndürüldüğünde ya da çoklu pencere modunda bir pencerenin boyutu değiştirildiğinde.

Jetpack WindowManager WindowMetricsCalculator sınıfı, mevcut ve maksimum pencere metriklerini almanıza olanak tanır. API düzeyi 30'da kullanıma sunulan platform WindowMetrics gibi WindowManager WindowMetrics da pencere sınırlarını sağlar ancak API, API düzeyi 14'e kadar geriye dönük uyumludur.

Pencere boyutu sınıflarını kullanma başlıklı makaleyi inceleyin.

Ek kaynaklar

Örnekler

  • Jetpack WindowManager: Jetpack WindowManager kitaplığının nasıl kullanılacağını gösteren örnek
  • Jetcaster : Compose ile masaüstü duruşu uygulaması

Codelab uygulamaları