È una cattiva pratica usare i margini negativi in ​​Android?


114

Demo del margine negativo:

                         inserisci qui la descrizione dell'immagine

Lo scenario

Viste sovrapposte impostando un margine negativo su una di esse in modo che invada il riquadro di delimitazione di un'altra vista.

Pensieri

Sembra funzionare come ti aspetteresti con la sovrapposizione dei layout se dovrebbero. Ma non voglio incorrere in un problema più grande per non aver fatto inconsapevolmente le cose per bene. Emulatori, dispositivi fisici, lo chiami, quando usi i margini negativi tutto sembra funzionare correttamente, una vista invade il riquadro di delimitazione delle viste di un'altra e, a seconda di come è dichiarata nel layout, sarà sopra o sotto l'altra vista.

Sono anche consapevole del fatto che dall'API 21 possiamo impostare gli attributi translationZe elevationper far apparire la vista sopra o sotto altre viste, ma la mia preoccupazione deriva fondamentalmente dal fatto che nella documentazione per gli layout_marginattributi è chiaramente specificato che i valori di margine dovrebbero essere positivi , lascia mi cito:

Estratto:
specifica lo spazio aggiuntivo sui lati sinistro, superiore, destro e inferiore di questa vista. Questo spazio è al di fuori dei limiti di questa vista. I valori del margine dovrebbero essere positivi . Deve essere un valore di dimensione, che è un numero in virgola mobile aggiunto a un'unità come "14,5 sp". Le unità disponibili sono: px (pixel), dp (pixel indipendenti dalla densità), sp (pixel scalati in base alla dimensione del carattere preferita), in (pollici), mm (millimetri) ...

Negli anni trascorsi da quando ho inizialmente posto questa domanda non ho avuto problemi con i margini negativi, ho cercato di evitare di usarli il più possibile, ma non ho riscontrato alcun problema, quindi anche se la documentazione afferma che, non lo sono troppo preoccupato per questo.


1
so che i test dell'espresso non saranno in grado di vedere l'oggetto se uno dei suoi margini è negativo ... quindi questo è un motivo per non usarli
Tim Boland

Risposte:


192

Nel 2010, @RomainGuy (ingegnere principale di Android) ha dichiarato che i margini negativi avevano un comportamento non specificato .

Nel 2011, @RomainGuy ha dichiarato che è possibile utilizzare margini negativi su LinearLayouteRelativeLayout .

Nel 2016, @RomainGuy ha dichiarato di non essere mai stato ufficialmente supportato e di non essere supportato daConstraintLayout .

Tuttavia è facile aggirare questa limitazione.

Aggiungi una vista di supporto (altezza 0dp, larghezza vincolata al genitore) nella parte inferiore della tua vista di base, in fondo aggiungi il margine che desideri.
Quindi posiziona la tua vista sotto questa, in modo che abbia effettivamente un margine "negativo" ma senza dover utilizzare alcun valore negativo non supportato.


1
Sembra essere una cosa innocua quindi, lasciare aperto nel caso qualcuno abbia qualche altra intuizione
Juan Cortés

1
@DrewLeSueur: non farei questa supposizione. Non ho idea di cosa significherebbe un riempimento negativo.
CommonsWare

1
@CommonsWare puoi dirmi, è possibile fare qualcosa del genere `- @ dimen / anyvalue"? Voglio chiamare il valore dichiarato ma negativo. Aiuto.
deadfish

2
@ 100kg: Scusa, ma non è supportato.
CommonsWare

21
Ho notato che in Android 4.4 KitKat qualcosa è cambiato per quanto riguarda i margini negativi (rispetto a 4.3; almeno su Asus Nexus 7). Si scopre che hai bisogno android:clipChildren="false"e android:clipToPadding="false"dove prima non lo facevi, o le cose si rompono in questo modo .
Jonik

18

Spero che questo possa aiutare qualcuno. Ecco un codice di esempio funzionante ConstraintLayoutbasato sulla risposta di @ CommonsWare:

Aggiungi una vista di supporto (altezza 0dp, larghezza vincolata al genitore) nella parte inferiore della tua vista di base, in fondo aggiungi il margine che desideri. Quindi posiziona la tua vista sotto questa, in modo che abbia effettivamente un margine "negativo" ma senza dover utilizzare alcun valore negativo non supportato.

Codice di esempio:

<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" />

Produzione:

inserisci qui la descrizione dell'immagine


16

Nel caso in cui desideri utilizzare un margine negativo, imposta una spaziatura sufficiente per il contenitore e il suo clipToPadding su false e imposta il margine negativo per i suoi figli in modo che non taglierà la visualizzazione figlio!


4

Potrebbe essere stata una cattiva pratica in passato, ma con Material Design e i suoi pulsanti di azione fluttuanti, sembra essere inevitabile e richiesto in molti casi ora. Fondamentalmente, quando hai due layout separati che non puoi mettere in un singolo RelativeLayout perché necessitano di una gestione nettamente separata (pensa all'intestazione e al contenuto, ad esempio), l'unico modo per sovrapporre il FAB è farlo sporgere da uno di questi layout che utilizzano margini negativi. E questo crea ulteriori problemi con le aree cliccabili.


3

Per me, e per quanto riguarda l'impostazione di un margine negativo su un TextView (mi rendo conto che l'OP si riferisce a un ViewGroup, ma stavo cercando problemi con l'impostazione dei margini negativi e sono atterrato qui) ... Ho trovato un problema con 4.0.3 ( API 15) SOLO e l'impostazione di android:layout_marginTopoandroid:layout_marginBottom su un valore negativo come -2dp.

Per qualche motivo TextView non viene visualizzato affatto. Sembra essere "andato" dalla vista (non solo invisibile).

Quando l'ho provato con le altre 3 versioni di layout_margin, non ho riscontrato il problema.

Nota che non l'ho provato su un dispositivo reale, questo sta usando un emulatore 4.0.3. Questa è la seconda cosa strana che ho scoperto che ha interessato solo 4.0.3, quindi la mia nuova regola è sempre testare con un emulatore 4.0.3 :)

Ho avuto successo con la riduzione del margine inferiore di un TextView usando android:lineSpacingExtra="-2dp"che funziona anche se mi capita di avere android:singleLine="true"(e quindi non avrei pensato che l'interlinea sarebbe un fattore).


1
Ho riscontrato un comportamento simile su un Nexus 4 (che è xhdpi) e 4.2.2. C'era un layout senza riempimento, sebbene un layout padre avesse il riempimento. C'era un TextView all'interno con marginTop negativo. Su 5.0 ha funzionato bene. Su 4.2.2 sia sul dispositivo che in un emulatore per Nexus 4, scompare. La soluzione era spostare il padding nel layout che conteneva TextView.
louielouie

3

No, non dovresti usare negative margin. invece dovresti usare translate. Anche se a volte il margine negativo funziona, quando si modifica il layout in modo programmabile, la traduzione sarebbe utile. E la visualizzazione non può superare lo schermo quando usi il margine.


0

Sapevo che era possibile solo per un periodo di tempo piuttosto breve. Ma non ci vedo alcun problema. Basta essere consapevoli delle dimensioni dello schermo e simili in modo da essere sicuri di non creare accidentalmente elementi che non dovrebbero apparire sovrapposti sullo schermo. (ad esempio, il testo sopra il testo è probabilmente una cattiva idea.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.