Büyük ve katlanmamış ekranlar ile benzersiz katlanmış durumlar, katlanabilir cihazlarda yeni kullanıcı deneyimlerine olanak tanır. Uygulamanızı katlanabilir cihazlara uygun hale getirmek için Jetpack WindowManager kitaplığını kullanın. Bu kitaplık, katlanabilir cihazların pencere özellikleriyle (ör. katlanma ve menteşe) ilgili bir API yüzeyi sağlar. Uygulamanız katlama özelliğini desteklediğinde, ö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 konusundaki kararlara yön verebilir.
Pencere bilgileri
Jetpack WindowManager'daki WindowInfoTracker arayüzü, pencere düzeni bilgilerini gösterir. Arayüzün windowLayoutInfo() yöntemi, uygulamanızı katlanabilir bir cihazın katlanma durumu hakkında bilgilendiren WindowLayoutInfo verileri akışını döndürür. WindowInfoTracker#getOrCreate() yöntemi, WindowInfoTracker öğesinin bir örneğini oluşturur.
WindowManager, Kotlin akışları ve Java geri çağırmaları kullanılarak WindowLayoutInfo veri toplanmasını destekler.
Kotlin akışları
WindowLayoutInfo veri toplamayı başlatmak ve durdurmak için repeatOnLifecycle kod bloğunun yaşam döngüsü en az STARTED olduğunda yürütüldüğü ve yaşam döngüsü STOPPED olduğunda durdurulduğu yeniden başlatılabilir yaşam döngüsü farkında olan bir eşzamanlı rutin kullanabilirsiniz. Yaşam döngüsü 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 toplar ve 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ığında bulunan geri çağırma uyumluluk katmanı, Kotlin akışı kullanmadan WindowLayoutInfo güncellemelerini toplamanıza olanak tanır. Yapı, WindowInfoTrackerCallbackAdapter sınıfını içerir. Bu sınıf, WindowInfoTracker öğesini uyarlayarak örneğin WindowLayoutInfo güncellemelerini almak için geri çağırmaları kaydetmeyi (ve kaydı silmeyi) destekler:
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'yı (2 veya 3 sürümü) kullanıyorsanız Kotlin akışı kullanmadan WindowLayoutInfo güncellemelerini toplamanıza olanak tanıyan Observable veya Flowable kullanmanızı sağlayan 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üncellemelerini 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ı, bir ekran penceresinin özelliklerini DisplayFeature öğeleri listesi olarak kullanılabilir hâle getirir.
FoldingFeature, aşağıdaki özellikleri de içeren katlanabilir ekranlar hakkında bilgi sağlayan bir DisplayFeature türüdür:
state: Cihazın katlanmış durumu,FLATveyaHALF_OPENEDorientation: Katlama veya menteşenin yönü,HORIZONTALveyaVERTICALocclusionType: Katlama veya menteşe, ekranın bir kısmını gizliyor mu?NONEveyaFULLisSeparating: Katlama veya menteşe, iki mantıksal ekran alanı oluşturuyor mu? Doğru veya yanlış.
Ekran iki görüntüleme alanına ayrıldığından katlanabilir cihazlar HALF_OPENED her zaman isSeparating olarak bildirir. Ayrıca, uygulama her iki ekrana da yayıldığında çift ekranlı bir cihazda isSeparating her zaman doğrudur.
FoldingFeature bounds özelliği (DisplayFeature öğesinden devralınır), katlama veya menteşe gibi katlanabilir bir özelliğin 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
Uygulamanız, FoldingFeature nesnesinde yer alan bilgileri kullanarak telefonu bir yüzeye yerleştirme, menteşeyi yatay konuma getirme ve katlanabilir ekranı yarıya kadar açma gibi duruşları destekleyebilir.
Masaüstü duruşu, kullanıcıların telefonlarını ellerinde tutmadan kullanabilmelerini sağlar. Masa üstü duruşu, medya izlemek, fotoğraf çekmek ve görüntülü görüşme yapmak için idealdir.
Cihazın masaüstü duruşunda olup olmadığını belirlemek için FoldingFeature.State ve FoldingFeature.Orientation 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ü duruşunda olduğunu öğrendikten sonra uygulama düzeninizi buna göre güncelleyin. Medya uygulamalarında bu genellikle oynatmanın katlanma çizgisinin üzerinde yerleştirilmesi ve kontroller ile ek içeriklerin, eller serbest görüntüleme veya dinleme deneyimi için hemen ardından konumlandırılması anlamına gelir.
Android 15 (API düzeyi 35) ve sonraki sürümlerde, cihazın mevcut durumundan bağımsız olarak bir cihazın masaüstü duruşunu destekleyip desteklemediğini tespit etmek için senkron bir API çağırabilirsiniz.
API, cihaz tarafından desteklenen duruşların bir listesini sağlar. Liste, masaüstü duruşunu içeriyorsa duruşu desteklemek için uygulama düzeninizi bölebilir ve masaüstü ile tam ekran düzenleri için uygulama kullanıcı arayüzünüzde 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
MediaPlayerActivityuygulaması: Katlanabilir cihazlara uygun bir video oynatıcı oluşturmak için Media3 Exoplayer ve WindowManager'ı nasıl kullanacağınızı öğrenin.Jetpack WindowManager ile katlanabilir cihazlarda kamera uygulamanızı optimize etme codelab: Fotoğrafçılık uygulamaları için masaüstü duruşunu nasıl uygulayacağınızı öğrenin. Vizörü ekranın üst yarısında (katlama çizgisinin üstünde), kontrolleri ise alt yarısında (katlama çizgisinin altında) gösterin.
Kitap duruşu
Kitap duruşu da benzersiz bir katlanabilir özellik. Bu duruşta cihaz yarıya kadar açılıyor ve menteşe dikey konumda oluyor. Kitap duruşu, e-kitap okumak için idealdir. Büyük ekranlı katlanabilir cihazlarda, ciltli kitap gibi açılan iki sayfalık düzenle kitap duruşu, gerçek kitap okuma deneyimini yakalar.
Ellerinizi kullanmadan fotoğraf çekerken farklı bir en boy oranı yakalamak istiyorsanız fotoğrafçılık için de kullanılabilir.
Kitap duruşunu, masaüstü duruşu için kullanılan tekniklerle aynı şekilde uygulayın. Tek fark, kodun katlama özelliği yönünün yatay yerine dikey olduğunu kontrol etmesi gerektiğidir:
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 cihazın yapılandırmasında değişiklik yapıldığında (ör. cihaz katlandığında veya açıldığında, döndürüldüğünde ya da çoklu pencere modunda bir pencerenin boyutu değiştirildiğinde) uygulamanın görüntüleme alanı değişebilir.
Jetpack WindowManager WindowMetricsCalculator sınıfı, mevcut ve maksimum pencere metriklerini almanızı sağlar. API düzeyi 30'da kullanıma sunulan platform gibi, WindowMetrics WindowManager
WindowMetrics de pencere sınırlarını sağlar ancak API, API düzeyi 14'e kadar geriye dönük olarak 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ğına dair örnek
- Jetcaster : Compose ile masaüstü duruşu uygulama
Codelab uygulamaları
- Jetpack WindowManager ile katlanabilir ve çift ekranlı cihazları destekleme
- Jetpack WindowManager ile katlanabilir cihazlarda kamera uygulamanızı optimize etme