Dengan layar besar yang dibentangkan dan bentuk lipatan unik memungkinkan pengalaman pengguna baru di perangkat foldable. Agar aplikasi Anda menjadi fold aware, gunakan library Jetpack WindowManager, yang menyediakan platform API untuk fitur jendela perangkat foldable seperti lipatan dan engsel. Jika aplikasi Anda fold aware, aplikasi tersebut dapat menyesuaikan tata letaknya menghindari penempatan konten penting di area lipatan atau engsel, dan gunakan lipatan dan engsel sebagai pemisah alami.
Memahami apakah perangkat mendukung konfigurasi seperti mode di atas meja atau buku dapat memandu keputusan untuk mendukung tata letak yang berbeda atau menyediakan fitur spesifik.
Informasi jendela
Antarmuka WindowInfoTracker
di Jetpack WindowManager mengekspos jendela
informasi tata letak. Metode windowLayoutInfo()
antarmuka menampilkan
aliran data WindowLayoutInfo
yang menginformasikan aplikasi Anda tentang perangkat foldable
status lipat perangkat. Metode WindowInfoTracker#getOrCreate()
membuat
dari WindowInfoTracker
.
WindowManager menyediakan dukungan untuk mengumpulkan data WindowLayoutInfo
menggunakan
Flow Kotlin dan callback Java.
Alur Kotlin
Untuk memulai dan menghentikan pengumpulan data WindowLayoutInfo
, Anda dapat menggunakan metode yang dapat dimulai ulang
coroutine berbasis siklus proses tempat blok kode repeatOnLifecycle
berada
dijalankan saat siklus proses setidaknya dalam status STARTED
dan dihentikan saat
siklus proses adalah STOPPED
. Eksekusi blok kode otomatis dimulai ulang
saat siklus proses dalam status STARTED
lagi. Pada contoh berikut, blok kode
mengumpulkan dan menggunakan data WindowLayoutInfo
:
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.
}
}
}
}
}
Callback Java
Lapisan kompatibilitas callback yang disertakan dalam
Dependensi androidx.window:window-java
memungkinkan Anda mengumpulkan
WindowLayoutInfo
diupdate tanpa menggunakan alur Kotlin. Artefak ini mencakup
class WindowInfoTrackerCallbackAdapter
, yang menyesuaikan
WindowInfoTracker
untuk mendukung pendaftaran callback (dan pembatalan pendaftaran) ke
terima update WindowLayoutInfo
, misalnya:
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.
});
}
}
}
Dukungan RxJava
Jika Anda sudah menggunakan RxJava
(versi 2
atau 3
),
Anda dapat memanfaatkan artefak
yang memungkinkan Anda menggunakan
Observable
atau Flowable
untuk mengumpulkan update WindowLayoutInfo
tanpa menggunakan alur Kotlin.
Lapisan kompatibilitas yang disediakan oleh androidx.window:window-rxjava2
dan
Dependensi androidx.window:window-rxjava3
menyertakan
WindowInfoTracker#windowLayoutInfoFlowable()
dan
Metode WindowInfoTracker#windowLayoutInfoObservable()
, yang memungkinkan
aplikasi Anda untuk menerima pembaruan WindowLayoutInfo
, misalnya:
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()
}
}
Fitur layar perangkat foldable
Class WindowLayoutInfo
Jetpack WindowManager membuat fitur
jendela tampilan yang tersedia sebagai daftar elemen DisplayFeature
.
FoldingFeature
adalah jenis DisplayFeature
yang memberikan informasi
tentang layar perangkat foldable, termasuk hal berikut:
state
: Status lipatan perangkat,FLAT
atauHALF_OPENED
orientation
: Orientasi lipatan atau engsel,HORIZONTAL
atauVERTICAL
occlusionType
: Apakah lipatan atau engsel menyembunyikan bagian layar,NONE
atauFULL
isSeparating
: Apakah lipatan atau engsel membuat dua area tampilan logis, benar atau salah
Perangkat foldable HALF_OPENED
selalu melaporkan isSeparating
sebagai benar
karena layar dipisahkan menjadi dua area tampilan. Selain itu, isSeparating
adalah
selalu benar (true) pada perangkat dua layar saat aplikasi menjangkau kedua
layar.
Properti bounds
FoldingFeature
(diwarisi dari DisplayFeature
)
mewakili persegi panjang pembatas fitur lipat seperti lipatan atau engsel.
Batas dapat digunakan untuk memosisikan elemen di layar yang terkait dengan fitur:
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. } } } }
Postur di atas meja
Dengan menggunakan informasi yang disertakan dalam objek FoldingFeature
, aplikasi Anda dapat
mendukung postur seperti di atas meja, di mana ponsel berada di permukaan, engselnya
dalam posisi horizontal, dan layar perangkat foldable terbuka setengah.
Postur di atas meja menawarkan kenyamanan kepada pengguna dalam mengoperasikan ponsel tanpa memegang ponsel. Postur mode di atas meja sangat bagus untuk menonton media, mengambil foto, dan melakukan panggilan video.

Gunakan FoldingFeature.State
dan FoldingFeature.Orientation
untuk menentukan
apakah perangkat dalam postur di atas meja:
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); }
Setelah mengetahui bahwa perangkat dalam postur mode di atas meja, perbarui tata letak aplikasi Anda sebagaimana mestinya. Untuk aplikasi media, pembaruan ini biasanya berarti menempatkan pemutaran di paruh atas dan kontrol posisi serta konten tambahan tepat di bawahnya untuk pengalaman menonton atau mendengarkan secara handsfree.
Di Android 15 (API level 35) dan yang lebih baru, Anda dapat memanggil API sinkron untuk mendeteksi apakah perangkat mendukung postur di atas meja, terlepas dari status perangkat saat ini.
API ini menyediakan daftar postur yang didukung oleh perangkat. Jika daftar berisi postur mode di atas meja, Anda dapat memisahkan tata letak aplikasi untuk mendukung postur dan jalankan pengujian A/B di UI aplikasi Anda untuk tata letak mode di atas meja dan layar penuh.
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. } }
Contoh
Aplikasi
MediaPlayerActivity
: Lihat cara menggunakan Media3 Exoplayer dan WindowManager untuk membuat pemutar video fold-aware.Codelab Mengoptimalkan aplikasi kamera di perangkat foldable dengan Jetpack WindowManager: Pelajari cara menerapkan postur di atas meja untuk aplikasi fotografi. Tampilkan jendela bidik di paruh atas layar (paruh atas) dan di paruh bawah (di paruh bawah).
Postur buku
Fitur unik lain dari perangkat foldable adalah postur buku, dengan perangkat terbuka setengah dan engsel vertikal. Postur buku sangat cocok untuk membaca e-book. Dengan tata letak dua halaman pada perangkat foldable layar besar yang dapat dilipat dan terbuka seperti buku, postur buku menciptakan pengalaman membaca buku sungguhan.
Mode ini juga dapat digunakan untuk fotografi jika Anda ingin mengambil aspek yang berbeda sambil mengambil gambar secara handsfree.
Terapkan postur buku dengan teknik yang sama dengan yang digunakan untuk postur mode di atas meja. Tujuan satu-satunya perbedaan adalah kode harus memeriksa apakah orientasi fitur lipat vertikal alih-alih horizontal:
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); }
Perubahan ukuran jendela
Area tampilan aplikasi dapat berubah sebagai akibat dari perubahan konfigurasi perangkat, misalnya, saat perangkat dilipat atau dibentangkan, diputar, atau jendela diubah ukurannya dalam mode multi-aplikasi.
Class WindowMetricsCalculator
Jetpack WindowManager memungkinkan Anda
mengambil metrik jendela saat ini dan maksimum. Seperti platform
WindowMetrics
yang diperkenalkan di API level 30, WindowManager
WindowMetrics
menyediakan batas jendela, tetapi API-nya kompatibel dengan versi lama
sampai dengan API level 14.
Lihat Menggunakan class ukuran jendela.
Referensi lainnya
Contoh
- Jetpack WindowManager: Contoh cara menggunakan Jetpack Library WindowManager
- Jetcaster : Implementasi postur mode di atas meja dengan Compose
Codelab
- Mendukung perangkat foldable dan perangkat dua layar dengan Jetpack WindowManager
- Mengoptimalkan aplikasi kamera di perangkat foldable dengan Jetpack WindowManager