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 funkcji kompozycyjnych, które określają granice szerokości i wysokości.

Na tej stronie opisujemy, jak modyfikatory łańcuchowe wpływają na ograniczenia, a także na pomiary i rozmieszczenie elementów kompozycyjnych.

Modyfikatory w drzewie interfejsu

Aby zrozumieć, jak modyfikatory wpływają na siebie nawzajem, warto zwizualizować ich wygląd w drzewie interfejsu generowanym na etapie tworzenia kompozycji. Więcej informacji znajdziesz w sekcji Kompozycja.

W drzewie interfejsu możesz zwizualizować modyfikatory jako węzły otoki 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ż 1 modyfikatora do funkcji kompozycyjnej powoduje utworzenie łańcucha 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 np. łączysz łańcuch clip i modyfikatora size, węzeł modyfikatora clip opakowuje węzeł modyfikatora size, który następnie opakowuje węzeł układu Image.

Na etapie układu algorytm, który spaceruje po drzewie, pozostaje taki sam, ale odwiedzany jest też każdy węzeł modyfikujący. W ten sposób modyfikator może zmienić wymagania dotyczące rozmiaru i położenie węzła modyfikatora lub układu, który jest opakowany.

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 obiektów Row i Column to po prostu węzły układu, które opisują, jak rozmieszczać elementy podrzędne.

Dotychczasowa struktura drzewa, ale teraz każdy węzeł ma po prostu prosty układ z wieloma modyfikatorami otaczającymi węzły.
Rysunek 2. Ta sama struktura drzewa co na ilustracji 1, ale elementy kompozycyjne w drzewie interfejsu są przedstawione jako łańcuchy modyfikatorów.

Podsumowując:

  • Modyfikatory obejmują pojedynczy węzeł modyfikatora lub układu.
  • Węzły układu mogą rozmieszczać wiele węzłów podrzędnych.

W kolejnych sekcjach opisujemy, jak korzystać z tego modelu psychicznego do analizowania łańcuchów modyfikatorów i jak wpływa on na rozmiar elementów kompozycyjnych.

Ograniczenia na etapie układu

Faza układu używa trzyetapowego algorytmu, który wyszukuje szerokość i wysokość każdego węzła układu oraz współrzędne x i y:

  1. Mierz elementy podrzędne: węzeł mierzy swoje elementy podrzędne, jeśli takie istnieją.
  2. Ustal własny rozmiar: na podstawie tych pomiarów węzeł decyduje o własnym rozmiarze.
  3. Umieść węzeł podrzędny: każdy węzeł podrzędny jest umieszczany względem jego własnej pozycji.

Constraints pomaga znaleźć odpowiednie rozmiary dla węzłów podczas pierwszych 2 etapów algorytmu. Ograniczenia określają minimalne i maksymalne granice szerokości i wysokości węzła. Gdy węzeł decyduje o swoim rozmiarze, zmierzony rozmiar powinien mieścić się w tym zakresie rozmiarów.

Typy ograniczeń

Ograniczenie może mieć jedną z tych wartości:

  • Ograniczony: węzeł ma maksymalną i minimalną szerokość i wysokość.
Ograniczone ograniczenia o różnych rozmiarach w kontenerze.
Rys. 3. Ograniczone ograniczenia.
  • Bez ograniczeń: węzeł nie jest ograniczony do żadnego rozmiaru. Granice maksymalnej 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. Nieograniczone ograniczenia.
  • Ścisły: węzeł ma spełniać wymagania dotyczące dokładnego rozmiaru. Minimalne i maksymalne granice mają taką samą wartość.
Dokładne ograniczenia zgodne z wymaganym dokładnym rozmiarem w kontenerze.
Rysunek 5. Ścisłe ograniczenia.
  • Kombinacja: węzeł korzysta z kombinacji powyższych 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 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 elementu podrzędnego.

Jak ograniczenia są przekazywane z zasady nadrzędnej do podrzędnej

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

Gdy węzeł nadrzędny mierzy swoje elementy podrzędne, podaje te ograniczenia każdemu podrzędnemu elementowi, aby poinformować je, jak duże lub małe mogą być te obiekty. Gdy decyduje o własnym rozmiarze, przestrzega też ograniczeń ustalonych przez jego rodziców.

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

  1. Aby określić rzeczywisty rozmiar, który ma zajmować, węzeł główny w drzewie interfejsu 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 ma wpływu na pomiary, przekierowuje ograniczenia do następnego modyfikatora. Ograniczenia są przekazywane do łańcucha modyfikatorów w niezmienionej postaci, chyba że zostanie osiągnięty modyfikator wpływający na pomiar. a następnie dostosowuje się do nich ograniczenia.
  3. Gdy dotrzesz do węzła, który nie ma żadnych elementów podrzędnych (nazywanych „węzłem liścia”), określa swój rozmiar na podstawie przekazanych ograniczeń i zwraca ten zakończony rozmiar do elementu nadrzędnego.
  4. Jednostka nadrzędna dostosowuje swoje ograniczenia na podstawie pomiarów elementu podrzędnego i wywołuje kolejny element podrzędny z tymi dostosowanymi ograniczeniami.
  5. Po zmierzeniu wszystkich elementów podrzędnych węzła nadrzędnego ustala on swój rozmiar i przekazuje go do swojego elementu nadrzędnego.
  6. W ten sposób całe drzewo przechodzimy przede wszystkim na głębokości. W końcu wszystkie węzły mają już wybrane rozmiary i etap pomiaru jest zakończony.

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

Modyfikatory wpływające na ograniczenia

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

Modyfikator size

Modyfikator size deklaruje preferowany rozmiar treści.

Na przykład poniższe drzewo interfejsu powinno zostać wyrenderowane w kontenerze 300dp przez 200dp. Ograniczenia są ograniczone, co pozwala na szerokość od 100dp do 300dp oraz wysokość od 100dp do 200dp:

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

Modyfikator size dostosowuje przychodzące ograniczenia tak, aby pasowały do przekazywanej do niej wartości. 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 dostosowuje ograniczenia na 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 rosnące ograniczenia. W drugim przypadku modyfikator rozmiaru możliwie najlepiej dostosowuje się do zbyt dużych ograniczeń, powodując w ten sposób ograniczenia, które wypełniają kontener.
Rysunek 9. Modyfikator size jak najściślej zgodny z przekazanym ograniczeniem.

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 wymaga mniejszej lub większego rozmiaru, musi przestrzegać podanych granic, więc nie zastępuje tych wartości:

Łańcuch dwóch modyfikatorów rozmiaru w drzewie UI i jego reprezentacja w kontenerze, który jest wynikiem przesłania pierwszej wartości, a nie drugiej.
Rysunek 10. Łańcuch dwóch modyfikatorów size, w którym druga wartość przekazywana (50dp) nie zastępuje pierwszej wartości (100dp).

Modyfikator requiredSize

Jeśli chcesz zastąpić przychodzące ograniczenia, użyj modyfikatora requiredSize zamiast size. Modyfikator requiredSize zastępuje przychodzące ograniczenia i przekazuje określony rozmiar jako dokładne granice.

Po przekazaniu rozmiaru 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 przychodzące ograniczenia 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 wysokość nie zostanie określona. I podobnie, za pomocą modyfikatora height możesz ustawić stałą wysokość, ale szerokość pozostaw nieokreśloną:

2 drzewa interfejsu: jedno z modyfikatorem szerokości i 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 pozwala ustawić dokładne minimalne i maksymalne ograniczenia szerokości i wysokości. Jeśli potrzebujesz szczegółowej kontroli nad ograniczeniami, użyj modyfikatora sizeIn.

Drzewo interfejsu z modyfikatorem sizeIn z ustawioną minimalną i maksymalną szerokością i wysokością oraz jego reprezentacją w kontenerze.
Rysunek 13. Modyfikator sizeIn z ustawionymi wartościami minWidth, maxWidth, minHeight i maxHeight.

Przykłady

Ta sekcja przedstawia i objaśnia dane wyjściowe kilku fragmentów kodu z łańcuchami modyfikatorów.

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

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

  • Modyfikator fillMaxSize zmienia ograniczenia tak, aby ustawić minimalną szerokość i wysokość na wartość maksymalną – 300dp i 200dp wysokości.
  • Mimo że modyfikator size ma używać rozmiaru 50dp, musi przestrzegać przychodzących ograniczeń minimalnych. Dlatego modyfikator size zwróci też dokładne granice ograniczenia 300 o 200, co spowoduje zignorowanie wartości podanej w modyfikatorze size.
  • Image przekracza te granice i raportuje rozmiar 300 o wartości 200, która jest przekazywana aż do wysokości drzewa.

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

Ten fragment kodu daje 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 resetuje minimalne ograniczenia. Mimo że funkcja fillMaxSize spowodowała stałe ograniczenia, wrapContentSize przywraca ją z powrotem do ograniczeń ograniczonych. Poniższy węzeł może ponownie zająć całą przestrzeń lub być od niej mniejszy.
  • Modyfikator size ustawia ograniczenia na minimalny i maksymalny próg 50.
  • Image przyjmuje rozmiar 50 o 50 i modyfikator size to odpowiednio.
  • Modyfikator wrapContentSize ma specjalną właściwość. Zabiera element podrzędny i umieszcza go w środku dostępnych minimalnych granic, które zostały do niego 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 funkcji kompozycyjnej i wyśrodkować ją w elemencie nadrzędnym.

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

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

  • Modyfikator clip nie zmienia ograniczeń.
    • Modyfikator padding obniża maksymalne ograniczenia.
    • Modyfikator size ustawia wszystkie ograniczenia na 100dp.
    • Image jest zgodny z tymi ograniczeniami i raportuje rozmiar 100 na 100dp.
    • Modyfikator padding dodaje wartość 10dp we wszystkich rozmiarach, więc zwiększa szerokość i wysokość o 20dp.
    • Na etapie rysowania modyfikator clip działa na obszarze roboczym 120 przez 120dp. Tworzy on więc maskę koła o tym rozmiarze.
    • Modyfikator padding wstawia treść za pomocą właściwości 10dp we wszystkich rozmiarach, więc zmniejsza rozmiar obszaru roboczego do 100 o 100dp.
    • W tym obszarze roboczym narysowany jest element Image. Obraz zostanie przycięty na podstawie pierwotnego okręgu 120dp, więc wynik nie będzie okrągły.