Duże rozłożone wyświetlacze i wyjątkowy sposób złożenia urządzenia pozwalają wygodnie urządzeniach składanych. Aby umożliwić korzystanie z aplikacji na składanych urządzeniach, użyj biblioteki Jetpack WindowManager, która udostępnia interfejs API do obsługi funkcji okien na składanych urządzeniach, takich jak składanie i zginanie. Gdy aplikacja jest składana, może dostosować swój układ. aby uniknąć umieszczania ważnych treści w częściach fałdowych lub zawiasach, i zawiasów jako naturalny separator.
Wiedza o tym, czy urządzenie obsługuje konfiguracje takie jak ułożenie na stole czy w księgu, może pomóc w podejmowaniu decyzji o obsługiwaniu różnych układów lub udostępnianiu określonych funkcji.
Informacje o oknie
Interfejs WindowInfoTracker
w Jetpack WindowManager udostępnia informacje o układzie okna. Metoda windowLayoutInfo()
interfejsu zwraca strumień danych WindowLayoutInfo
, który informuje aplikację o stanie składania składanego urządzenia. Metoda WindowInfoTracker#getOrCreate()
tworzy
wystąpienia WindowInfoTracker
.
WindowManager zapewnia obsługę zbierania danych z WindowLayoutInfo
przy użyciu
Przepływy Kotlin i wywołania zwrotne Java.
Płynące w kotlinie
Aby rozpocząć i zatrzymać zbieranie danych w usłudze WindowLayoutInfo
, możesz użyć polecanego ponownie
wspólnoty dostosowanej do cyklu życia, w której znajduje się blok kodu repeatOnLifecycle
jest wykonywane, gdy cykl życia wynosi co najmniej STARTED
i zostaje zatrzymany, gdy
cykl życia wynosi STOPPED
. Wykonanie bloku kodu jest automatycznie ponownie uruchamiane
gdy cykl życia ponownie wynosi STARTED
. W tym przykładzie blok kodu zbiera i używa danych 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.
}
}
}
}
}
Wywołania zwrotne w Javie
Warstwa zgodności wywołania zwrotnego zawarta w zależności androidx.window:window-java
umożliwia zbieranie aktualizacji WindowLayoutInfo
bez używania kodu Kotlin. Artefakt zawiera
klasy WindowInfoTrackerCallbackAdapter
, która dostosowuje
WindowInfoTracker
do obsługi rejestrowania (i wyrejestrowania) wywołań zwrotnych do
otrzymywać aktualizacje z zakresu WindowLayoutInfo
, na przykład:
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.
});
}
}
}
Obsługa RxJava
Jeśli używasz już RxJava
(w wersji 2
lub 3
), możesz korzystać z elementów, które umożliwiają użycie Observable
lub Flowable
do zbierania aktualizacji WindowLayoutInfo
bez korzystania z przepływu w Kotlinie.
Warstwa zgodności udostępniana przez interfejsy androidx.window:window-rxjava2
oraz
Zależności androidx.window:window-rxjava3
obejmują
WindowInfoTracker#windowLayoutInfoFlowable()
i
WindowInfoTracker#windowLayoutInfoObservable()
, które pozwalają włączyć
aby otrzymywać WindowLayoutInfo
aktualizacje, na przykład:
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()
}
}
Funkcje składanych ekranów
Klasa WindowLayoutInfo
obiektu Jetpack WindowManager tworzy funkcje
okno wyświetlania dostępne w postaci listy elementów DisplayFeature
.
FoldingFeature
to typ elementu DisplayFeature
, który zawiera informacje
o składanych ekranach, w tym:
state
: stan złożenia urządzenia,FLAT
lubHALF_OPENED
orientation
: orientacja strony widocznej na ekranie lub zawiasu,HORIZONTAL
lubVERTICAL
occlusionType
: czy zawias lub zawias ukrywa część wyświetlacza:NONE
lubFULL
isSeparating
: czy złożenie lub zawias tworzy 2 logiczne obszary wyświetlacza (prawda lub fałsz).
Urządzenie składane, które jest HALF_OPENED
, zawsze zgłasza isSeparating
jako prawda
bo ekran jest podzielony na dwa obszary. Ponadto na urządzeniu z dwoma ekranami isSeparating
jest zawsze true, gdy aplikacja obejmuje oba ekrany.
Właściwość FoldingFeature
bounds
(odziedziczona z DisplayFeature
) reprezentuje prostokąt ograniczający element składany, np. zawias.
Za pomocą tych granic możesz umieszczać elementy na ekranie względem funkcji:
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. } } } }
Postawa przy stole
Korzystając z informacji zawartych w obiekcie FoldingFeature
, aplikacja może obsługiwać tryby takie jak stolik, w którym telefon leży na powierzchni, zawias jest w pozycji poziomej, a ekran składany jest w połowie otwarty.
Konstrukcja stołu zapewnia użytkownikom wygodę i umożliwia korzystanie z telefonów bez trzymając telefon w rękach. Pozycja na stole jest idealna do oglądania multimediów, robienia zdjęć i prowadzenia rozmów wideo.

Użyj FoldingFeature.State
i FoldingFeature.Orientation
, aby określić, czy urządzenie jest w pozycji poziomej:
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); }
Gdy ustalisz, że urządzenie jest w stanie stołu, zaktualizuj układ aplikacji odpowiednio się zmienia. W przypadku aplikacji multimedialnych oznacza to zwykle umieszczenie odtwarzania nad resztą interfejsu oraz elementów sterujących i treści dodatkowych poniżej, aby umożliwić oglądanie lub słuchanie bez użycia rąk.
W Androidzie 15 (poziom interfejsu API 35) i nowszych możesz wywołać interfejs API synchronicznego, aby wykryć, czy urządzenie obsługuje pozycję na stole niezależnie od jego bieżącego stanu.
Interfejs API udostępnia listę pozycji obsługiwanych przez urządzenie. Jeśli lista zawiera stan stołu, możesz podzielić układ aplikacji do obsługi stanu i wykonywać testy A/B w interfejsie aplikacji dla układów na stołach i w trybie pełnoekranowym.
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. } }
Przykłady
aplikacja
MediaPlayerActivity
: dowiedz się, jak użyć Media3 Exoplayer i WindowManager do utworzenia odtwarzacza wideo obsługującego składany ekran.Optymalizacja aplikacji aparatu na składanych urządzeniach za pomocą Jetpack WindowManager Codelab: dowiedz się, jak zaimplementować tryb stołu w aplikacjach do fotografowania. Program wizjer w górnej części ekranu (w części strony widocznej na ekranie), w dolnej części strony (w części strony widocznej po przewinięciu).
Postawa podczas czytania
Kolejną unikalną funkcją składanego urządzenia jest tryb książki, w którym urządzenie jest w połowie otwarte, a zawias jest pionowy. Stan książki świetnie sprawdza się podczas czytania e-booków. Układ dwustronny na dużym ekranie, który można otworzyć jak książkę, pozwala na odwzorowanie pozycji czytania prawdziwej książki.
Możesz też używać go do robienia zdjęć, jeśli chcesz uzyskać inny format obrazu podczas robienia zdjęć bez użycia rąk.
Wdróż stan książki przy użyciu tych samych technik, które są stosowane w przypadku stanu stołu. Jedyną różnicą jest to, że kod powinien sprawdzić, czy orientacja funkcji zwijania w pionie zamiast w poziomie:
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); }
Zmiany rozmiaru okna
Obszar wyświetlania aplikacji może się zmieniać w zależności od konfiguracji urządzenia, na przykład gdy urządzenie jest złożone lub rozłożone, gdy jest obracane lub gdy zmienia się rozmiar okna w trybie wielookiennym.
Klasa Jetpack WindowManager WindowMetricsCalculator
umożliwia:
pobierze bieżące i maksymalne wskaźniki dotyczące okien. Polub platformę
WindowMetrics
wprowadziliśmy w interfejsie API poziomu 30 – WindowManager
WindowMetrics
podaje granice okien, ale interfejs API jest zgodny wstecznie
aż do poziomu API 14.
Zobacz Używanie klas rozmiaru okna.
Dodatkowe materiały
Próbki
- Jetpack WindowManager: przykład korzystania z Jetpacka Biblioteka WindowManager
- Jetcaster: implementacja postawy stołu w Compose
Ćwiczenia z programowania
- Obsługa składanych urządzeń i urządzeń z dwoma ekranami za pomocą Jetpack WindowManager
- Zoptymalizuj aplikację aparatu na urządzeniach składanych dzięki Jetpack WindowManager