Kolejność ograniczeń i modyfikatorów

W narzędziu Compose możesz połączyć wiele modyfikatorów, aby zmienić wygląd i sposób działania funkcji kompozycyjnej. Te łańcuchy modyfikatorów mogą wpływać na ograniczenia przekazywane do komponentów, które definiują granice szerokości i wysokości.

Na tej stronie wyjaśniamy, jak zmodyfikowane modyfikatory wpływają na ograniczenia, a w konsekwencji na pomiar i umiejscowienie komponentów.

Modyfikatory w drzewie interfejsu

Aby zrozumieć, jak modyfikatory wpływają na siebie nawzajem, warto zwizualizować, jak są one wyświetlane w drzewie interfejsu użytkownika, które jest generowane w trakcie fazy tworzenia. Więcej informacji znajdziesz w sekcji Kompozycja.

W drzewie interfejsu użytkownika modyfikatory możesz wizualizować jako węzły opakowania dla węzłów układu:

Kod elementów kompozycyjnych i modyfikatorów oraz ich wizualna reprezentacja w postaci drzewa interfejsu.
Rysunek 1. Modyfikatory opakowujące węzły układu w drzewie interfejsu.

Dodanie więcej niż jednego modyfikatora do kompozytowanego tworzy łańcuch modyfikatorów. W przypadku połączenia wielu modyfikatorów każdy węzeł modyfikujący opakowuje resztę łańcucha i węzeł układu w obrębie łańcucha. Jeśli na przykład połączysz modyfikator clip z modyfikatorem size, węzeł modyfikatora clip otacza węzeł modyfikatora size, który z kolei otacza węzeł układu Image.

W fazie układu algorytm przechodzący po drzewie pozostaje taki sam, ale odwiedza też każdy węzeł modyfikatora. Dzięki temu modyfikator może zmienić wymagania dotyczące rozmiaru i umieszczenie modyfikatora lub węzła układu, który otacza.

Jak widać na rys. 2, samo wdrożenie elementów kompozycyjnych Image i Text składa się z łańcucha modyfikatorów opakowujących pojedynczy węzeł układu. Implementacje RowColumn to po prostu węzły układu, które opisują sposób rozmieszczania elementów podrzędnych.

Struktura drzewa z wcześniej, ale teraz każdy węzeł to tylko prosty układ z wiele modyfikatorami otaczającymi go.
Rysunek 2. Ta sama struktura drzewa jak na rysunku 1, ale z elementami kompozytowymi w drzewie interfejsu użytkownika wizualizowanymi jako łańcuchy modyfikatorów.

Podsumowując:

  • Modyfikatory otaczają pojedynczy modyfikator lub węzeł układu.
  • Węzły układu mogą zawierać wiele węzłów podrzędnych.

W kolejnych sekcjach opisujemy, jak za pomocą tego modelu mentalnego analizować łańcuch modyfikatorów i jak wpływa on na rozmiar komponentów.

Ograniczenia w etapu układu

Etap układu polega na znalezieniu szerokości, wysokości i współrzędnych x, y każdego węzła układu za pomocą algorytmu o 3 etapach:

  1. Pomiar podrzędnych: węzeł mierzy swoje podrzędne, jeśli takie istnieją.
  2. Ustal własny rozmiar: na podstawie tych pomiarów węzeł decyduje o własnym rozmiarze.
  3. Umieszczanie podrzędnych węzłów: każdy podrzędny węzeł jest umieszczany względem pozycji węzła.

Constraints pomagają znaleźć odpowiednie rozmiary węzłów w pierwszych 2 krokach algorytmu. Ograniczenia określają minimalne i maksymalne wartości szerokości i wysokości węzła. Gdy węzeł określa swój rozmiar, zmierzony rozmiar powinien mieścić się w tym zakresie.

Typy ograniczeń

Ograniczenie może być jednym z tych elementów:

  • Ograniczony: węzeł ma maksymalną i minimalną szerokość i wysokość.
Ograniczone ograniczenia o różnych rozmiarach w kontenerze.
Rysunek 3. Ograniczenia z zakresem działania.
  • Bez ograniczeń: węzeł nie jest ograniczony żadnym rozmiarem. Maksymalne wartości szerokości i wysokości są ustawione na nieskończoność.
Nieograniczone ograniczenia, których szerokość i wysokość są ustawione na nieskończoność. Ograniczenia wykraczają poza kontener.
Rysunek 4. Ograniczenia bez ograniczeń.
  • Dokładne: węzeł musi spełniać dokładne wymagania dotyczące rozmiaru. Minimalne i maksymalne wartości mają tę samą wartość.
Dokładne ograniczenia, które odpowiadają dokładnemu wymaganiu dotyczącemu rozmiaru w kontenerze.
Rysunek 5. Ograniczenia dokładne.
  • Kombinacja: węzeł stosuje kombinację wymienionych powyżej typów ograniczeń. Ograniczenie może na przykład ograniczyć szerokość, zezwalając na nieograniczoną maksymalną wysokość, lub ustawić dokładną szerokość, a jednocześnie ograniczoną wysokość.
Dwa kontenery, które pokazują kombinacje ograniczonych i nieograniczonych ograniczeń oraz dokładne wartości szerokości i wysokości.
Rysunek 6. Kombinacje ograniczonych i nieograniczonych ograniczeń oraz dokładnych szerokości i wysokości.

W następnej sekcji opisujemy, jak te ograniczenia są przekazywane z elementu nadrzędnego do podrzędnego.

Jak ograniczenia są przekazywane z elementu nadrzędnego do podrzędnego

W pierwszym kroku algorytmu opisanym w sekcji Ograniczenia w etapie układu ograniczenia są przekazywane z elementu nadrzędnego do podrzędnego w drzewie interfejsu.

Gdy węzeł nadrzędny mierzy swoje węzły podrzędne, przekazuje te ograniczenia do każdego węzła podrzędnego, aby wiedział, jak duży lub mały może być. Następnie, gdy określa swój rozmiar, musi też przestrzegać ograniczeń przekazanych przez swoich rodziców.

Ogólnie algorytm działa w ten sposób:

  1. Aby określić rozmiar, który chce zająć, węzeł główny w drzewie interfejsu użytkownika mierzy swoje elementy podrzędne i przekazuje te same ograniczenia do pierwszego elementu podrzędnego.
  2. Jeśli element podrzędny jest modyfikatorem, który nie wpływa na pomiar, przekazuje ograniczenia do następnego modyfikatora. Ograniczenia są przekazywane w łańcuchu modyfikatorów bez zmian, chyba że zostanie osiągnięty modyfikator, który wpływa na pomiar. a następnie dostosowuje się do nich ograniczenia.
  3. Gdy zostanie osiągnięty węzeł, który nie ma żadnych węzłów podrzędnych (nazywany „węzłem końcowym”), określa on swój rozmiar na podstawie podanych ograniczeń i zwraca ten rozmiar do węzła nadrzędnego.
  4. Jednostka nadrzędna dostosowuje swoje ograniczenia na podstawie pomiarów elementu podrzędnego i wywołuje kolejne z wykorzystaniem tych dostosowanych ograniczeń.
  5. Gdy wszystkie elementy podrzędne zostaną zmierzone, węzeł nadrzędny określa swój rozmiar i przekazuje go swojemu rodzicowi.
  6. W ten sposób całe drzewo przechodzimy przede wszystkim na głębokości. Ostatecznie wszystkie węzły określają swoje rozmiary i kończy się etap pomiaru.

Szczegółowy przykład znajdziesz w filmie Ograniczenia i kolejność modyfikatorów.

Modyfikatory wpływające na ograniczenia

Z poprzedniej sekcji wiesz już, że niektóre modyfikatory mogą wpływać na rozmiar ograniczeń. W sekcjach poniżej opisujemy konkretne modyfikatory, które wpływają na ograniczenia.

modyfikator size

Modyfikator size określa preferowany rozmiar treści.

Na przykład to drzewo interfejsu powinno być renderowane w kontenerze 300dp 200dp. Ograniczenia są ograniczone, co pozwala na szerokość w zakresie od 100dp do 300dp oraz wysokość w zakresie od 100dp do 200dp:

Część drzewa interfejsu z modyfikatorem rozmiaru otaczającym węzeł układu oraz przedstawieniem ograniczeń ustawionych przez modyfikator rozmiaru w kontenerze.
Rysunek 7. Ograniczone ograniczenia w drzewie interfejsu użytkownika i jego reprezentacja w kontenerze.

Modyfikator size dostosowuje docierające ograniczenia do wartości, która została mu przekazana. W tym przykładzie wartość to 150dp:

Tak samo jak na ilustracji 7, z tą różnicą, że modyfikator rozmiaru dostosowuje przychodzące ograniczenia do przekazywanej do niej wartości.
Rysunek 8. Modyfikator size dostosowujący ograniczenia do wartości 150dp.

Jeśli szerokość i wysokość są mniejsze niż najmniejsza granica ograniczenia lub większe od największego, modyfikator jak najdokładniej dopasowuje przekazywane ograniczenia, jednocześnie przestrzegając podanych ograniczeń:

2 drzewa UI i odpowiadające im reprezentacje w kontenerach. W pierwszym przypadku modyfikator rozmiaru akceptuje ograniczenia wejściowe, a w drugim dostosowuje się do ograniczeń zbyt dużych w jak największym stopniu, co powoduje, że ograniczenia wypełniają kontener.
Rysunek 9. Modyfikator size, który jak najdokładniej przestrzega przekazanego ograniczenia.

Pamiętaj, że łączenie wielu modyfikatorów size nie działa. Pierwszy modyfikator size ustawia zarówno minimalne, jak i maksymalne ograniczenia na stałą wartość. Nawet jeśli drugi modyfikator rozmiaru zażąda mniejszego lub większego rozmiaru, musi on nadal mieścić się w dokładnych granicach, więc nie zastąpi tych wartości:

Łańcuch dwóch modyfikatorów rozmiaru w drzewie interfejsu użytkownika i jego reprezentacja w kontenerze, która jest wynikiem przekazanej pierwszej wartości, a nie drugiej.
Rysunek 10. Łańcuch 2 modyfikatorów size, w którym druga wartość przekazana (50dp) nie zastępuje pierwszej wartości (100dp).

modyfikator requiredSize

Jeśli chcesz, aby twój węzeł zastąpił docierające ograniczenia, użyj modyfikatora requiredSize zamiast size. Modyfikator requiredSize zastępuje docierające ograniczenia i przekazuje podany przez Ciebie rozmiar jako dokładne granice.

Gdy rozmiar zostanie przekazany z powrotem do drzewa, węzeł podrzędny zostanie wyśrodkowany w dostępnej przestrzeni:

Modyfikator rozmiaru i wymagany rozmiar w drzewie interfejsu oraz odpowiednia reprezentacja w kontenerze. Wymagane ograniczenia modyfikatora rozmiaru zastępują ograniczenia związane z modyfikatorem rozmiaru.
Rysunek 11. Modyfikator requiredSize zastępuje ograniczenia przychodzące z modyfikatora size.

Modyfikatory width i height

Modyfikator size dostosowuje zarówno szerokość, jak i wysokość ograniczeń. Za pomocą modyfikatora width możesz ustawić stałą szerokość, ale pozostawić nieokreśloną wysokość. I podobnie, za pomocą modyfikatora height możesz ustawić stałą wysokość, ale szerokość pozostaw nieokreśloną:

Dwa drzewa interfejsu: jedno z modyfikatorem szerokości i jego reprezentacją kontenera, a drugie z modyfikatorem wysokości i jego reprezentacją.
Rysunek 12. Modyfikatory width i height ustawiają odpowiednio stałą szerokość i wysokość.

modyfikator sizeIn

Modyfikator sizeIn umożliwia ustawienie dokładnych ograniczeń minimalnych i maksymalnych dla szerokości i wysokości. Jeśli potrzebujesz szczegółowej kontroli nad ograniczeniami, użyj modyfikatora sizeIn.

drzewo interfejsu użytkownika z modyfikatorem sizeIn z ustawionymi minimalną i maksymalną szerokością oraz wysokością, a także jego reprezentacją w kontenerze;
Rysunek 13. Modyfikator sizeIn z ustawionymi wartościami minWidth, maxWidth, minHeightmaxHeight.

Przykłady

Ta sekcja pokazuje i wyjaśnia dane wyjściowe z kilku fragmentów kodu z łańcuchowymi modyfikatorami.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .size(50.dp)
)

Ten fragment kodu zwraca te dane wyjściowe:

  • Modyfikator fillMaxSize zmienia ograniczenia, aby ustawić minimalną szerokość i wysokość na maksymalną wartość – 300dp w szerokości i 200dp – w wysokości.
  • Mimo że modyfikator size chce użyć rozmiaru 50dp, musi on nadal przestrzegać minimalnych ograniczeń wejściowych. Dlatego modyfikator size będzie też zwracać dokładne granice ograniczenia 300 przez 200, ignorując przy tym wartość podawaną w modyfikatorze size.
  • Element Image podąża za tymi granicami i podaje rozmiar 300 według 200, który jest przekazywany w górę po drzewie.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .wrapContentSize()
        .size(50.dp)
)

Ten fragment kodu generuje następujące dane wyjściowe:

  • Modyfikator fillMaxSize dostosowuje ograniczenia tak, aby ustawić minimalną szerokość i wysokość do wartości maksymalnej – 300dp szerokości i 200dp w wysokości.
  • Modyfikator wrapContentSize zeruje ograniczenia minimalne. Chociaż fillMaxSize spowodowało ograniczenie, wrapContentSize przywraca je do ograniczeń. Następny węzeł może znowu zajmować całą przestrzeń lub być mniejszy niż cała przestrzeń.
  • Modyfikator size ustawia minimalne i maksymalne wartości parametru 50.
  • Image przyjmuje rozmiar 50 o 50 i modyfikator size to odpowiednio.
  • Modyfikator wrapContentSize ma specjalną właściwość. Zabiera ono swoje dziecko i umieszcza je w środku dostępnych minimalnych granic, które zostały mu przekazane. Rozmiar, który przekazuje do elementów nadrzędnych, jest więc równy minimalnemu progowi, który został do niego przesłany.

Łącząc tylko 3 modyfikatory, możesz zdefiniować rozmiar kompozytu i wyśrodkować go w rodzicu.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .clip(CircleShape)
        .padding(10.dp)
        .size(100.dp)
)

Ten fragment kodu powoduje wyświetlenie tych danych wyjściowych:

  • Modyfikator clip nie zmienia ograniczeń.
    • Modyfikator padding obniża maksymalne ograniczenia.
    • Modyfikator size ustawia wszystkie ograniczenia na 100dp.
    • Funkcja Image przestrzega tych ograniczeń i podaje rozmiar 100 w ramach 100dp.
    • Modyfikator padding dodaje 10dp do wszystkich rozmiarów, co zwiększa zgłaszaną szerokość i wysokość o 20dp.
    • W fazie rysowania modyfikator clip działa na płótnie o wymiarach 120 przez 120dp. W tym celu tworzy maskę koła o takim rozmiarze.
    • Modyfikator padding wstawia zawartość obiektu o 10dp we wszystkich rozmiarach, więc zmniejsza rozmiar obszaru roboczego do 100 o 100dp.
    • W tym obszarze roboczym narysowany jest element Image. Obraz jest przycięty na podstawie oryginalnego koła o promieniu 120dp, więc wynik nie jest okrągły.