Czy używanie ujemnych marż w systemie Android jest złą praktyką?

114

Demo ujemnej marży:

                         wprowadź opis obrazu tutaj

Scenariusz

Nakładające się widoki poprzez ustawienie ujemnego marginesu dla jednego z nich, tak aby naruszał obwiednię innego widoku.

Myśli

Wydaje się, że działa tak, jak można się spodziewać, z nakładaniem się układów, jeśli powinny. Ale nie chcę napotkać większego problemu, ponieważ nieświadomie nie robię rzeczy dobrze. Emulatory, fizyczne urządzenia, jak to nazywasz, kiedy używasz ujemnych marginesów, wszystko wydaje się działać poprawnie, jeden widok narusza obwiednię innych widoków iw zależności od tego, jak jest zadeklarowany w układzie, będzie powyżej lub poniżej drugiego widoku.

Jestem też świadomy, że od API 21 możemy ustawić translationZi elevation atrybuty, aby widok pojawia się powyżej lub poniżej innych poglądów, ale moja sprawa zasadniczo wynika z faktu, że w dokumentacji dla layout_marginatrybutów to wyraźnie określić, że wartości marginesów powinna być dodatnia , niech cytuję:

Fragment:
określa dodatkową przestrzeń po lewej, górnej, prawej i dolnej stronie tego widoku. Ta przestrzeń jest poza granicami tego widoku. Wartości marginesów powinny być dodatnie . Musi to być wartość wymiaru, która jest liczbą zmiennoprzecinkową z dołączoną jednostką, np. „14,5sp”. Dostępne jednostki to: px (piksele), dp (piksele niezależne od gęstości), sp (piksele skalowane w oparciu o preferowany rozmiar czcionki), w (cale), mm (milimetry) ...

Przez lata, odkąd zadałem to pytanie, nie miałem żadnych problemów z ujemnymi marżami, starałem się unikać ich używania w jak największym stopniu, ale nie napotkałem żadnych problemów, więc mimo że dokumentacja mówi, że nie jestem zbyt martwiłem się o to.

Juan Cortés
źródło
1
wiem, że testy espresso nie będą w stanie zobaczyć obiektu, jeśli jeden z jego marginesów będzie ujemny ... więc to powód, aby ich nie używać
Tim Boland

Odpowiedzi:

193

W 2010 roku @RomainGuy (główny inżynier Android) stwierdził, że ujemne marże miały nieokreślone zachowanie .

W 2011 roku @RomainGuy stwierdził, że można stosować ujemne marże na LinearLayoutiRelativeLayout .

W 2016 roku @RomainGuy stwierdził, że nigdy nie były oficjalnie wspierane i nie będą obsługiwane przezConstraintLayout .

Jednak łatwo jest obejść to ograniczenie.

Dodaj widok pomocnika (wysokość 0 dp, szerokość ograniczona do elementu nadrzędnego) u dołu widoku podstawowego, u dołu dodaj żądany margines.
Następnie umieść swój widok poniżej tego, skutecznie pozwalając mu mieć „ujemny” margines, ale bez konieczności używania żadnej nieobsługiwanej wartości ujemnej.

CommonsWare
źródło
1
Wydaje się więc być rzeczą nieszkodliwą, pozostawiając otwartą na wypadek, gdyby ktoś miał jakiś inny wgląd
Juan Cortés
1
@DrewLeSueur: Nie zakładałbym takiego założenia. Nie mam pojęcia, co oznaczałoby w ogóle negatywne wypełnienie.
CommonsWare
1
@CommonsWare Czy możesz mi powiedzieć, czy można zrobić coś takiego `- @ dimen / anyvalue"? Chcę wywołać zadeklarowaną wartość, ale ujemną. Pomoc.
deadfish
2
@ 100kg: Przepraszamy, ale to nie jest obsługiwane.
CommonsWare
21
Zauważyłem, że w Androidzie 4.4 KitKat coś się zmieniło w zakresie ujemnych marż (w porównaniu do 4.3; przynajmniej na Asus Nexus 7). Okazuje się, że potrzebujesz android:clipChildren="false"i android:clipToPadding="false"gdzie wcześniej nie robiłeś, albo coś tak się psuje .
Jonik,
18

Mam nadzieję, że to komuś pomoże. Oto działający przykładowy kod przy użyciu ConstraintLayoutna podstawie odpowiedzi @ CommonsWare:

Dodaj widok pomocnika (wysokość 0 dp, szerokość ograniczona do elementu nadrzędnego) u dołu widoku podstawowego, u dołu dodaj żądany margines. Następnie umieść swój widok poniżej tego, skutecznie pozwalając mu mieć „ujemny” margines, ale bez konieczności używania żadnej nieobsługiwanej wartości ujemnej.

Przykładowy kod:

<TextView
    android:id="@+id/below"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#F1B36D"
    android:padding="30dp"
    android:text="I'm below"
    android:textColor="#ffffff"
    android:textSize="48sp"
    android:textAlignment="center"
    tools:layout_editor_absoluteX="129dp"
    tools:layout_editor_absoluteY="0dp" />

<android.support.v4.widget.Space
    android:id="@+id/space"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:layout_marginBottom="32dp"
    app:layout_constraintBottom_toBottomOf="@+id/below"
    app:layout_constraintLeft_toLeftOf="@id/below"
    app:layout_constraintRight_toRightOf="@id/below" />

<TextView
    android:id="@+id/top"
    android:layout_width="100dp"
    android:layout_height="60dp"
    android:textAlignment="center"
    android:textColor="#ffffff"
    android:text="I'M ON TOP!"
    android:background="#676563"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/space" />

Wynik:

wprowadź opis obrazu tutaj

Vikasdeep Singh
źródło
16

Jeśli chcesz użyć ujemnego marginesu, ustaw wystarczające wypełnienie kontenera i jego clipToPadding na false i ustaw ujemny margines dla jego elementów podrzędnych, aby nie przycinał widoku potomnego!

Ali
źródło
4

W przeszłości mogła to być zła praktyka, ale dzięki Material Design i jego pływającym przyciskom akcji wydaje się być nieunikniona i wymagana w wielu przypadkach teraz. Zasadniczo, jeśli masz dwa oddzielne układy, których nie możesz umieścić w jednym RelativeLayout, ponieważ wymagają one wyraźnie oddzielnej obsługi (na przykład nagłówek i zawartość), jedynym sposobem na nałożenie FAB jest sprawienie, by wystawał z jednego układy z ujemnymi marginesami. A to stwarza dodatkowe problemy z klikalnymi obszarami.

Gábor
źródło
3

Dla mnie, a jeśli chodzi o ustawienie ujemnej marży na TextView (zdaję sobie sprawę, że OP odnosi się do ViewGroup, ale szukałem problemów z ustawieniem ujemnych marginesów i wylądowałem tutaj) ... Znalazłem problem z 4.0.3 ( API 15) TYLKO i ustawienie android:layout_marginToplubandroid:layout_marginBottom na wartość ujemną, taką jak -2dp.

Z jakiegoś powodu TextView w ogóle się nie wyświetla. Wydaje się, że „zniknął” z widoku (nie tylko niewidoczny).

Kiedy wypróbowałem to z innymi 3 wersjami layout_margin, nie widziałem problemu.

Zauważ, że nie próbowałem tego na prawdziwym urządzeniu, używa emulatora 4.0.3. To druga dziwna rzecz, którą znalazłem, a która dotyczyła tylko wersji 4.0.3, więc moja nowa zasada brzmi: zawsze teście z 4.0.3 emulatora :)

Udało mi się zmniejszyć dolny margines TextView, używając tego, android:lineSpacingExtra="-2dp"co działa, mimo że tak się stało android:singleLine="true"(i nie pomyślałbym, że odstępy między wierszami będą czynnikiem).

GaryAmundson
źródło
1
Znalazłem podobne zachowanie na Nexusie 4 (który jest xhdpi) i 4.2.2. Był układ bez dopełnienia, chociaż układ nadrzędny miał dopełnienie. Wewnątrz znajdował się TextView z ujemnym marginTop. W wersji 5.0 działało dobrze. W 4.2.2 zarówno na urządzeniu, jak iw emulatorze dla Nexusa 4, znika. Rozwiązaniem było przeniesienie dopełnienia do układu zawierającego TextView.
louielouie
3

Nie, nie powinieneś używać negative margin. zamiast tego powinieneś użyć translate. Nawet jeśli ujemny margines czasem zadziała, kiedy programowo zmienisz układ, translate by pomogło. Widok nie przepełnia ekranu, gdy używasz marginesów.

Cheung Sean
źródło
0

Wiem tylko, że było to możliwe przez dość krótki okres. Ale nie widzę z tym problemu. Po prostu pamiętaj o rozmiarach ekranu i tym podobnych, więc na pewno nie zrobisz przypadkowo elementów, które nie powinny nakładać się na ekran. (tzn. tekst na górze to prawdopodobnie zły pomysł).

FoamyGuy
źródło