Platforma przejść Androida umożliwia animowanie wszelkiego rodzaju ruchu w interfejsie, ponieważ udostępnia układy początkowy i końcowy. Możesz wybrać typ animacji, np. zanikanie widoków lub zmianę ich rozmiarów, a framework przejścia określi, jak animować przejście od układu początkowego do końcowego.
Platforma przejścia obejmuje te funkcje:
- Animacje na poziomie grupy: stosuj efekty animacji do wszystkich widoków w hierarchii widoków.
- Wbudowane animacje: używaj gotowych animacji do tworzenia popularnych efektów, takich jak zanikanie lub ruch.
- Obsługa plików zasobów: wczytywanie hierarchii widoków i wbudowanych animacji z plików zasobów układu.
- Wywołania zwrotne cyklu życia: otrzymuj wywołania zwrotne, które zapewniają kontrolę nad animacją i procesem zmiany hierarchii.
Przykładowy kod, który animuje przejścia między zmianami układu, znajdziesz w sekcji BasicTransition.
Podstawowy proces animacji między 2 układami wygląda tak:
- Utwórz obiekt
Scenedla układów początkowego i końcowego. Scena układu początkowego jest jednak często określana automatycznie na podstawie bieżącego układu. - Utwórz
Transitionobiekt, aby określić typ animacji. - Wywołaj
TransitionManager.go(), a system uruchomi animację, aby zamienić układy.
Diagram na rysunku 1 przedstawia relacje między układami, scenami, przejściem i animacją końcową.
Rysunek 1. Podstawowa ilustracja pokazująca, jak framework przejść tworzy animację.
Tworzenie sceny
Sceny przechowują stan hierarchii widoków, w tym wszystkie widoki i wartości ich właściwości. Framework przejść może uruchamiać animacje między sceną początkową a końcową.
Sceny możesz tworzyć z pliku zasobu układu lub z grupy widoków w kodzie. Scena początkowa przejścia jest jednak często określana automatycznie na podstawie bieżącego interfejsu.
Scena może też definiować własne działania, które są wykonywane po jej zmianie. Ta funkcja jest przydatna do czyszczenia ustawień widoku po przejściu do sceny.
Tworzenie sceny na podstawie zasobu układu
Możesz utworzyć instancję Scene bezpośrednio z pliku zasobu układu. Używaj tej techniki, gdy hierarchia widoków w pliku jest w większości statyczna.
Wynikowa scena reprezentuje stan hierarchii widoków w momencie utworzenia instancji Scene. Jeśli zmienisz hierarchię widoków, odtwórz scenę. Framework tworzy scenę na podstawie całej hierarchii widoków w pliku. Nie możesz utworzyć sceny z części pliku układu.
Aby utworzyć instancję Scene z pliku zasobu layoutu, pobierz z layoutu główny węzeł sceny jako ViewGroup. Następnie wywołaj funkcję Scene.getSceneForLayout() z korzeniem sceny i identyfikatorem zasobu pliku układu, który zawiera hierarchię widoków sceny.
Określanie układów scen
Fragmenty kodu w pozostałej części tej sekcji pokazują, jak utworzyć 2 różne sceny z tym samym elementem głównym sceny. Fragmenty kodu pokazują też, że możesz wczytać wiele niezwiązanych ze sobą obiektów Scene bez sugerowania, że są one ze sobą powiązane.
Przykład zawiera te definicje układu:
- Główny układ aktywności z etykietą tekstową i elementem podrzędnym
FrameLayout. ConstraintLayoutpierwszej sceny z 2 polami tekstowymi.ConstraintLayoutdla drugiej sceny z tymi samymi 2 polami tekstowymi w innej kolejności.
Przykład został zaprojektowany tak, aby cała animacja odbywała się w układzie podrzędnym głównego układu aktywności. Etykieta tekstowa w głównym układzie pozostaje statyczna.
Główny układ aktywności jest zdefiniowany w ten sposób:
res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/master_layout"> <TextView android:id="@+id/title" ... android:text="Title"/> <FrameLayout android:id="@+id/scene_root"> <include layout="@layout/a_scene" /> </FrameLayout> </LinearLayout>
Ta definicja układu zawiera pole tekstowe i element podrzędny FrameLayout dla głównego węzła sceny. Układ pierwszej sceny jest zawarty w głównym pliku układu.
Dzięki temu aplikacja może wyświetlać go jako część początkowego interfejsu użytkownika, a także wczytywać go do sceny, ponieważ platforma może wczytywać do sceny tylko cały plik układu.
Układ pierwszej sceny jest zdefiniowany w ten sposób:
res/layout/a_scene.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/scene_container" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/text_view1" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="Text Line 1" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/> <TextView android:id="@+id/text_view2" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="Text Line 2" app:layout_constraintTop_toBottomOf="@id/text_view1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
Układ drugiej sceny zawiera te same 2 pola tekstowe (o tych samych identyfikatorach), ale w innej kolejności. Definicja:
res/layout/another_scene.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/scene_container" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/text_view2" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="Text Line 2" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" /> <TextView android:id="@+id/text_view1" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="Text Line 1" app:layout_constraintTop_toBottomOf="@id/text_view2" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
Generowanie scen na podstawie układów
Po utworzeniu definicji 2 układów z ograniczeniami możesz uzyskać scenę dla każdego z nich. Pozwala to przełączać się między tymi 2 konfiguracjami interfejsu. Aby uzyskać scenę, potrzebujesz odwołania do jej głównego elementu i identyfikatora zasobu układu.
Ten fragment kodu pokazuje, jak uzyskać odniesienie do głównego węzła sceny i utworzyć 2 obiekty Scene z plików układu:
Kotlin
val sceneRoot: ViewGroup = findViewById(R.id.scene_root) val aScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.a_scene, this) val anotherScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.another_scene, this)
Java
Scene aScene; Scene anotherScene; // Create the scene root for the scenes in this app. sceneRoot = (ViewGroup) findViewById(R.id.scene_root); // Create the scenes. aScene = Scene.getSceneForLayout(sceneRoot, R.layout.a_scene, this); anotherScene = Scene.getSceneForLayout(sceneRoot, R.layout.another_scene, this);
W aplikacji są teraz 2 obiekty Scene oparte na hierarchiach widoków. Obie sceny używają głównego węzła sceny zdefiniowanego przez element FrameLayout w pliku res/layout/activity_main.xml.
Tworzenie sceny w kodzie
Możesz też utworzyć instancję Scene w kodzie z obiektu ViewGroup. Użyj tej techniki, gdy modyfikujesz hierarchie widoków bezpośrednio w kodzie lub gdy generujesz je dynamicznie.
Aby utworzyć scenę z hierarchii widoków w kodzie, użyj konstruktora
Scene(sceneRoot, viewHierarchy). Wywołanie tego konstruktora jest równoznaczne z wywołaniem funkcji Scene.getSceneForLayout(), gdy plik układu został już rozwinięty.
Poniższy fragment kodu pokazuje, jak utworzyć instancję Scene z elementu głównego sceny i hierarchii widoków sceny w kodzie:
Kotlin
val sceneRoot = someLayoutElement as ViewGroup val viewHierarchy = someOtherLayoutElement as ViewGroup val scene: Scene = Scene(sceneRoot, viewHierarchy)
Java
Scene mScene; // Obtain the scene root element. sceneRoot = (ViewGroup) someLayoutElement; // Obtain the view hierarchy to add as a child of // the scene root when this scene is entered. viewHierarchy = (ViewGroup) someOtherLayoutElement; // Create a scene. mScene = new Scene(sceneRoot, mViewHierarchy);
Tworzenie działań w scenie
Platforma umożliwia definiowanie niestandardowych działań na scenie, które system wykonuje podczas wchodzenia na scenę lub wychodzenia z niej. W wielu przypadkach definiowanie niestandardowych działań sceny jest niepotrzebne, ponieważ framework automatycznie animuje przejście między scenami.
Działania w scenie przydają się w tych przypadkach:
- Aby animować widoki, które nie znajdują się w tej samej hierarchii. Możesz animować widoki w scenach początkowych i końcowych za pomocą działań dotyczących scen wyjścia i wejścia.
- Aby animować widoki, których platforma przejść nie może animować automatycznie, np. obiekty
ListView. Więcej informacji znajdziesz w sekcji Ograniczenia.
Aby udostępnić niestandardowe działania w scenie, zdefiniuj działania jako obiekty Runnable i przekaż je do funkcji Scene.setExitAction() lub Scene.setEnterAction(). Framework wywołuje funkcję setExitAction() na scenie początkowej przed uruchomieniem animacji przejścia i funkcję setEnterAction() na scenie końcowej po uruchomieniu animacji przejścia.
Stosowanie przejścia
Framework przejścia reprezentuje styl animacji między scenami za pomocą obiektu Transition. Możesz utworzyć instancję Transition za pomocą wbudowanych podklas, takich jak AutoTransition i Fade, lub zdefiniować własne przejście.
Następnie możesz uruchomić animację między scenami, przekazując punkt końcowy Scene i Transition do TransitionManager.go().
Cykl życia przejścia jest podobny do cyklu życia aktywności i reprezentuje stany przejścia, które framework monitoruje między rozpoczęciem a zakończeniem animacji. W ważnych stanach cyklu życia platforma wywołuje funkcje zwrotne, które możesz zaimplementować, aby dostosować interfejs użytkownika na różnych etapach przejścia.
Tworzenie przejścia
W poprzedniej sekcji pokazaliśmy, jak tworzyć sceny reprezentujące stan różnych hierarchii widoków. Po określeniu scen początkowej i końcowej, między którymi chcesz się przełączać, utwórz obiekt Transition definiujący animację.
Platforma umożliwia określenie wbudowanego przejścia w pliku zasobu i rozszerzenie go w kodzie lub utworzenie instancji wbudowanego przejścia bezpośrednio w kodzie.
Tabela 1. wbudowane typy przejść;
| Klasa | Tag | Efekt |
|---|---|---|
AutoTransition |
<autoTransition/> |
Domyślne przeniesienie. Zanikanie, przesuwanie i zmiana rozmiaru, a potem pojawianie się widoków w tej kolejności. |
ChangeBounds |
<changeBounds/> |
Przesuwa i zmienia rozmiar widoków. |
ChangeClipBounds |
<changeClipBounds/> |
Rejestruje View.getClipBounds() przed i po zmianie sceny oraz animuje te zmiany podczas przejścia. |
ChangeImageTransform |
<changeImageTransform/> |
Rejestruje macierz ImageView przed zmianą sceny i po niej oraz animuje ją podczas przejścia. |
ChangeScroll |
<changeScroll/> |
Rejestruje właściwości przewijania elementów docelowych przed i po zmianie sceny oraz animuje wszelkie zmiany. |
ChangeTransform |
<changeTransform/> |
Rejestruje skalę i rotację widoków przed zmianą sceny i po niej oraz animuje te zmiany podczas przejścia. |
Explode |
<explode/> |
Śledzi zmiany widoczności widoków docelowych na scenach początkowej i końcowej oraz przesuwa widoki do lub z krawędzi sceny. |
Fade |
<fade/> |
fade_in zanika w widokach.fade_out przyciemnia widoki.fade_in_out (domyślne) wykonuje fade_out, a potem fade_in.
|
Slide |
<slide/> |
Śledzi zmiany widoczności widoków docelowych w scenach początkowej i końcowej oraz przesuwa widoki do lub z jednej z krawędzi sceny. |
Tworzenie instancji przejścia z pliku zasobów
Ta technika umożliwia modyfikowanie definicji przejścia bez zmiany kodu aktywności. Ta technika jest też przydatna do oddzielania złożonych definicji przejść od kodu aplikacji, jak pokazano w sekcji określania wielu przejść.
Aby określić wbudowane przejście w pliku zasobów:
- Dodaj katalog
res/transition/do projektu. - Utwórz w tym katalogu nowy plik zasobu XML.
- Dodaj węzeł XML dla jednego z wbudowanych przejść.
Na przykład ten plik zasobów określa przejście Fade:
res/transition/fade_transition.xml
<fade xmlns:android="http://schemas.android.com/apk/res/android" />
Poniższy fragment kodu pokazuje, jak utworzyć instancję Transition w aktywności z pliku zasobu:
Kotlin
var fadeTransition: Transition = TransitionInflater.from(this) .inflateTransition(R.transition.fade_transition)
Java
Transition fadeTransition = TransitionInflater.from(this). inflateTransition(R.transition.fade_transition);
Tworzenie instancji przejścia w kodzie
Ta technika jest przydatna do dynamicznego tworzenia obiektów przejścia, jeśli modyfikujesz interfejs użytkownika w kodzie, oraz do tworzenia prostych wbudowanych instancji przejścia z niewielką liczbą parametrów lub bez nich.
Aby utworzyć instancję wbudowanego przejścia, wywołaj jeden z konstruktorów publicznych w podklasach klasy Transition. Na przykład ten fragment kodu tworzy instancję przejścia Fade:
Kotlin
var fadeTransition: Transition = Fade()
Java
Transition fadeTransition = new Fade();
Stosowanie przejścia
Przejście zwykle stosuje się do zmiany hierarchii widoków w odpowiedzi na zdarzenie, np. działanie użytkownika. Rozważmy na przykład aplikację do wyszukiwania: gdy użytkownik wpisze wyszukiwane hasło i kliknie przycisk wyszukiwania, aplikacja przechodzi do sceny przedstawiającej układ wyników, stosując przejście, które powoduje zanikanie przycisku wyszukiwania i pojawianie się wyników wyszukiwania.
Aby zmienić scenę podczas stosowania przejścia w odpowiedzi na zdarzenie w aktywności, wywołaj funkcję klasy TransitionManager.go() z końcową sceną i instancją przejścia, która ma być używana w animacji, jak pokazano w tym fragmencie kodu:
Kotlin
TransitionManager.go(endingScene, fadeTransition)
Java
TransitionManager.go(endingScene, fadeTransition);
Framework zmienia hierarchię widoków w korzeniu sceny na hierarchię widoków z końcowej sceny, uruchamiając animację określoną przez instancję przejścia. Scena początkowa to scena końcowa z ostatniego przejścia. Jeśli nie ma poprzedniego przejścia, scena początkowa jest określana automatycznie na podstawie bieżącego stanu interfejsu użytkownika.
Jeśli nie określisz instancji przejścia, menedżer przejść może zastosować automatyczne przejście, które w większości sytuacji będzie odpowiednie. Więcej informacji znajdziesz w dokumentacji API klasy TransitionManager.
Wybieranie konkretnych widoków docelowych
Domyślnie framework stosuje przejścia do wszystkich widoków w scenach początkowej i końcowej. W niektórych przypadkach możesz chcieć zastosować animację tylko do podzbioru widoków w scenie. Framework umożliwia wybieranie konkretnych widoków, które chcesz animować. Na przykład framework nie obsługuje animowania zmian w obiektach ListView, więc nie próbuj ich animować podczas przejścia.
Każdy widok, w którym animowana jest zmiana, nazywa się elementem docelowym. Możesz wybrać tylko elementy docelowe, które są częścią hierarchii widoków powiązanej ze sceną.
Aby usunąć co najmniej jeden widok z listy celów, przed rozpoczęciem przejścia wywołaj metodę
removeTarget(). Aby dodać do listy miejsc docelowych tylko określone widoki, wywołaj funkcję addTarget(). Więcej informacji znajdziesz w dokumentacji API klasy
Transition.
Określanie wielu przejść
Aby animacja wywoływała jak największe wrażenie, dopasuj ją do rodzaju zmian, które zachodzą między scenami. Jeśli na przykład usuwasz niektóre widoki i dodajesz inne między scenami, animacja zanikania lub pojawiania się zapewnia wyraźną wskazówkę, że niektóre widoki nie są już dostępne. Jeśli przenosisz widoki w różne miejsca na ekranie, lepiej jest animować ruch, aby użytkownicy zauważyli nowe położenie widoków.
Nie musisz wybierać tylko jednej animacji, ponieważ framework przejść umożliwia łączenie efektów animacji w zestaw przejść, który zawiera grupę poszczególnych wbudowanych lub niestandardowych przejść.
Aby zdefiniować zestaw przejść z kolekcji przejść w XML, utwórz plik zasobów w katalogu res/transitions/ i wymień przejścia w elemencie TransitionSet. Na przykład poniższy fragment kodu pokazuje, jak określić zestaw przejść, który ma takie samo działanie jak klasa AutoTransition:
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:transitionOrdering="sequential"> <fade android:fadingMode="fade_out" /> <changeBounds /> <fade android:fadingMode="fade_in" /> </transitionSet>
Aby rozwinąć zestaw przejść do obiektu TransitionSet w kodzie, wywołaj funkcję TransitionInflater.from() w aktywności. Klasa TransitionSet rozszerza klasę Transition, więc możesz jej używać z menedżerem przejść tak samo jak każdej innej instancji Transition.
Stosowanie przejścia bez scen
Zmiana hierarchii widoków to nie jedyny sposób modyfikowania interfejsu użytkownika. Możesz też wprowadzać zmiany, dodając, modyfikując i usuwając widoki podrzędne w bieżącej hierarchii.
Możesz na przykład wdrożyć interakcję wyszukiwania z jednym układem. Zacznij od układu z polem wpisywania wyszukiwania i ikoną wyszukiwania. Aby zmienić interfejs użytkownika i wyświetlić wyniki, usuń przycisk wyszukiwania, gdy użytkownik go naciśnie, wywołując funkcję ViewGroup.removeView(), i dodaj wyniki wyszukiwania, wywołując funkcję ViewGroup.addView().
Możesz zastosować to podejście, jeśli alternatywą jest posiadanie 2 hierarchii, które są niemal identyczne. Zamiast tworzyć i utrzymywać 2 osobne pliki układu, które różnią się tylko nieznacznie, możesz mieć 1 plik układu zawierający hierarchię widoków, którą modyfikujesz w kodzie.
Jeśli wprowadzisz zmiany w bieżącej hierarchii widoków w ten sposób, nie musisz tworzyć sceny. Zamiast tego możesz utworzyć i zastosować przejście między 2 stanami hierarchii widoków za pomocą opóźnionego przejścia. Ta funkcja frameworka przejść zaczyna się od bieżącego stanu hierarchii widoków, rejestruje zmiany wprowadzane w widokach i stosuje przejście, które animuje zmiany, gdy system ponownie rysuje interfejs użytkownika.
Aby utworzyć opóźnione przejście w ramach jednej hierarchii widoków, wykonaj te czynności:
- Gdy wystąpi zdarzenie wywołujące przejście, wywołaj funkcję
TransitionManager.beginDelayedTransition()podając widok nadrzędny wszystkich widoków, które chcesz zmienić, oraz przejście, którego chcesz użyć. Framework przechowuje bieżący stan widoków podrzędnych i wartości ich właściwości. - Wprowadź zmiany w widokach podrzędnych zgodnie z potrzebami. Framework rejestruje zmiany wprowadzane w widokach podrzędnych i ich właściwościach.
- Gdy system ponownie rysuje interfejs użytkownika zgodnie z wprowadzonymi zmianami, platforma animuje zmiany między stanem pierwotnym a nowym.
Przykład poniżej pokazuje, jak animować dodawanie widoku tekstu do hierarchii widoków za pomocą opóźnionej zmiany. Pierwszy fragment kodu pokazuje plik definicji układu:
res/layout/activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/mainLayout" android:layout_width="match_parent" android:layout_height="match_parent" > <EditText android:id="@+id/inputText" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" /> ... </androidx.constraintlayout.widget.ConstraintLayout>
Kolejny fragment kodu pokazuje animację dodawania widoku tekstu:
MainActivity
Kotlin
setContentView(R.layout.activity_main) val labelText = TextView(this).apply { text = "Label" id = R.id.text } val rootView: ViewGroup = findViewById(R.id.mainLayout) val mFade: Fade = Fade(Fade.IN) TransitionManager.beginDelayedTransition(rootView, mFade) rootView.addView(labelText)
Java
private TextView labelText; private Fade mFade; private ViewGroup rootView; ... // Load the layout. setContentView(R.layout.activity_main); ... // Create a new TextView and set some View properties. labelText = new TextView(this); labelText.setText("Label"); labelText.setId(R.id.text); // Get the root view and create a transition. rootView = (ViewGroup) findViewById(R.id.mainLayout); mFade = new Fade(Fade.IN); // Start recording changes to the view hierarchy. TransitionManager.beginDelayedTransition(rootView, mFade); // Add the new TextView to the view hierarchy. rootView.addView(labelText); // When the system redraws the screen to show this update, // the framework animates the addition as a fade in.
Definiowanie wywołań zwrotnych cyklu życia przejścia
Cykl życia przejścia jest podobny do cyklu życia działania. Reprezentuje stany przejściowe, które framework monitoruje w okresie między wywołaniem funkcji TransitionManager.go() a zakończeniem animacji. W ważnych stanach cyklu życia platforma wywołuje funkcje zwrotne zdefiniowane przez interfejs TransitionListener.
Wywołania zwrotne cyklu życia przejścia są przydatne np. do kopiowania wartości właściwości widoku z początkowej hierarchii widoków do końcowej hierarchii widoków podczas zmiany sceny. Nie możesz po prostu skopiować wartości z widoku początkowego do widoku w hierarchii widoku końcowego, ponieważ hierarchia widoku końcowego nie jest rozwijana, dopóki przejście nie zostanie zakończone. Zamiast tego musisz zapisać wartość w zmiennej, a potem skopiować ją do końcowej hierarchii widoków, gdy platforma zakończy przejście. Aby otrzymywać powiadomienia o zakończeniu przenoszenia, zaimplementuj w swojej aktywności funkcję TransitionListener.onTransitionEnd().
Więcej informacji znajdziesz w dokumentacji interfejsu API klasy TransitionListener.
Ograniczenia
W tej sekcji znajdziesz niektóre znane ograniczenia platformy przejść:
- Animacje zastosowane do elementu
SurfaceViewmogą nie wyświetlać się prawidłowo.SurfaceViewsą aktualizowane z wątku innego niż wątek interfejsu, więc aktualizacje mogą być niespójne z animacjami innych widoków. - Niektóre typy przejść mogą nie dawać oczekiwanego efektu animacji, gdy są stosowane do
TextureView. - Klasy, które rozszerzają
AdapterView, np.ListView, zarządzają widokami podrzędnymi w sposób niezgodny z ramami przejść. Jeśli spróbujesz animować widok na podstawieAdapterView, wyświetlacz urządzenia może przestać odpowiadać. - Jeśli spróbujesz zmienić rozmiar
TextViewz animacją, tekst przeskoczy w nowe miejsce, zanim obiekt zostanie całkowicie zmieniony. Aby uniknąć tego problemu, nie animuj zmiany rozmiaru widoków zawierających tekst.