Duże rozłożone ekrany i wyjątkowy sposób złożenia urządzenia pozwalają wygodniej korzystać z urządzeń składanych. Aby Twoja aplikacja była widoczna bez przewijania, użyj biblioteki Jetpack WindowManager, która udostępnia interfejs API do obsługi funkcji w oknie urządzenia składanego, takich jak złożenie czy zawias. Aplikacja może dostosować swój układ, aby uniknąć umieszczania ważnych treści w zawiasach i farbach, i używać zawiasów oraz fałdów jako naturalnych separatorów.
Informacje o oknie
Interfejs WindowInfoTracker
w programie Jetpack WindowManager udostępnia informacje o układzie okien. Metoda windowLayoutInfo()
interfejsu zwraca strumień danych WindowLayoutInfo
, który informuje aplikację o stanie złożenia urządzenia składanego. Metoda WindowInfoTracker
getOrCreate()
tworzy instancję WindowInfoTracker
.
WindowManager obsługuje zbieranie danych WindowLayoutInfo
przy użyciu przepływów Kotlin i wywołań zwrotnych Java.
Kotlin
Aby rozpocząć i zatrzymać zbieranie danych w usłudze WindowLayoutInfo
, możesz użyć ponownego uruchomienia uwzględniającego cykl życia, w którym blok kodu repeatOnLifecycle
jest wykonywany, gdy cykl życia wynosi co najmniej STARTED
i zatrzymuje się, gdy cykl życia wynosi STOPPED
. Wykonanie bloku kodu jest automatycznie ponownie uruchamiane po powrocie cyklu życia STARTED
. W poniższym przykładzie blok kodu zbiera i wykorzystuje dane 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łań zwrotnych zawarty w zależności androidx.window:window-java
umożliwia zbieranie aktualizacji WindowLayoutInfo
bez użycia platformy Kotlin Flow. Artefakt zawiera klasę WindowInfoTrackerCallbackAdapter
, która dostosowuje WindowInfoTracker
do obsługi rejestrowania (i wyrejestrowania) wywołań zwrotnych, aby otrzymywać aktualizacje 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 korzystasz już z RxJava
(wersja 2
lub 3
), możesz skorzystać z artefaktów umożliwiających gromadzenie WindowLayoutInfo
aktualizacji za pomocą urządzenia Observable
lub Flowable
bez użycia przepływu Kotlin.
Warstwa zgodności udostępniana przez zależności androidx.window:window-rxjava2
i androidx.window:window-rxjava3
obejmuje metody WindowInfoTracker#windowLayoutInfoFlowable()
i WindowInfoTracker#windowLayoutInfoObservable()
, które umożliwiają aplikacji otrzymywanie aktualizacji WindowLayoutInfo
, 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 the WindowLayoutInfo observable
disposable?.dispose()
}
}
Funkcje składanych ekranów
Klasa WindowLayoutInfo
usługi Jetpack WindowManager udostępnia funkcje okna wyświetlania w postaci listy elementów DisplayFeature
.
FoldingFeature
to typ elementu DisplayFeature
, który zawiera informacje o składanych wyświetlaczach, m.in.:
state
: stan złożenia urządzenia,FLAT
lubHALF_OPENED
orientation
: orientacja strony widocznej na ekranie lub zawiasu,HORIZONTAL
lubVERTICAL
.occlusionType
: czy złożenie lub zawias zakrywa część wyświetlacza,NONE
lubFULL
isSeparating
: określa, czy zawias lub strona zwinięcia tworzy 2 logiczne obszary wyświetlania – true lub false (prawda) lub false (fałsz).
W przypadku urządzenia składanego, które jest HALF_OPENED
, zawsze zgłaszana jest wartość isSeparating
jako prawda, ponieważ ekran jest podzielony na 2 obszary wyświetlania. Oprócz tego zasada isSeparating
ma wartość prawda na urządzeniu z 2 ekranami, gdy aplikacja obejmuje oba ekrany.
Właściwość FoldingFeature
bounds
(odziedziczona z DisplayFeature
) reprezentuje prostokąt ograniczający element strony zawijanej, taki jak zawias lub zawinięcie. Granice mogą służyć do określania pozycji elementów na ekranie względem danego obiektu.
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { ... lifecycleScope.launch(Dispatchers.Main) { lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { // Safely collects from windowInfoRepo 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() .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 } } } }
Tryb na stole
Dzięki informacjom zawartym w obiekcie FoldingFeature
aplikacja może obsługiwać różne stany, np. tryb stołu,
Telefon jest umieszczony na płaskiej powierzchni, zawias jest ustawiony poziomo, a składany ekran jest w połowie otwarty.
Tryb Na stole zapewnia użytkownikom wygodę obsługi telefonu bez trzymając telefon w rękach. Tryb Na stole świetnie nadaje się do oglądania multimediów, robienia zdjęć i prowadzenia rozmów wideo.
Użyj formatu FoldingFeature.State
i FoldingFeature.Orientation
:
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 urządzenie będzie w trybie Na stole, zaktualizuj odpowiednio układ aplikacji. W przypadku aplikacji do multimediów zwykle oznacza to umieszczenie odtwarzania w części strony widocznej na ekranie znajdują się elementy sterujące i materiały dodatkowe poniżej, aby można było oglądać i słuchać treści bez użycia rąk.
Przykłady
Aplikacja
MediaPlayerActivity
: Zobacz, jak używać Media3 Exoplayer WindowManager, aby utworzyć rozłożony odtwarzacz wideo.Zaawansowane funkcje aparatu – ćwiczenia z programowania: dowiedz się, jak wdrożyć tryb stołu w aplikacjach fotograficznych. Pokaż wizjer w górnej części ekranu, w części strony widocznej na ekranie i elementach sterujących w dolnej części, w części strony widocznej po przewinięciu.
Tryb rezerwacji
Inną wyjątkową cechą urządzenia składanego jest tryb książki, w którym urządzenie jest w połowie otwarte. a zawias jest ustawiony pionowo. Tryb książki świetnie sprawdza się podczas czytania e-booków. Ma dwustronicowy na dużym, składanym, otwartym ekranie, który przypomina książkę połączoną z widoczną książką, prawdziwej książki.
Przydaje się to też do fotografowania, gdy chcesz robić zdjęcia bez użycia rąk w innym formacie obrazu.
Zaimplementuj tryb książki przy użyciu tych samych metod co w trybie Na stole. Jedyną różnicą jest to, powinien sprawdzić, czy funkcja zwijania ma orientację pionową, a nie poziomą:
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); }
Zmiana rozmiaru okna
Obszar wyświetlania aplikacji może się zmienić w wyniku zmiany konfiguracji urządzenia, na przykład po złożeniu lub rozłożeniu urządzenia, obróceniu go albo zmianie rozmiaru okna w trybie wielu okien.
Klasa Jetpack WindowManager WindowMetricsCalculator
umożliwia pobieranie bieżących i maksymalnych wskaźników okien. Podobnie jak w przypadku platformy WindowMetrics
wprowadzonej na poziomie interfejsu API 30, narzędzie WindowManager WindowMetrics
podaje granice okien, ale interfejs API jest zgodny wstecznie do poziomu 14.
Zobacz Klasy rozmiaru okna.
Dodatkowe materiały
Próbki
- Jetpack WindowManager: przykład użycia biblioteki Jetpack WindowManager.
- Jetcaster: implementacja stanu tabel za pomocą Compose
Ćwiczenia z programowania
- Obsługa urządzeń składanych i z 2 ekranami za pomocą programu Jetpack WindowManager
- Odkryj funkcje aparatu
Polecane dla Ciebie
- Uwaga: tekst linku wyświetla się, gdy JavaScript jest wyłączony
- Obsługa urządzeń składanych i z 2 ekranami za pomocą programu Jetpack WindowManager
- Zoptymalizuj aplikację aparatu na urządzeniach składanych dzięki Jetpack WindowManager
- Tryb zgodności urządzenia