¿Es una mala práctica utilizar márgenes negativos en Android?

114

Demostración de margen negativo:

                         ingrese la descripción de la imagen aquí

El escenario

Superposición de vistas estableciendo un margen negativo en una de ellas para que invada el cuadro delimitador de otra vista.

Pensamientos

Parece funcionar de la manera que cabría esperar con la superposición de los diseños si deberían hacerlo. Pero no quiero encontrarme con un problema mayor por no hacer las cosas bien sin saberlo. Emuladores, dispositivos físicos, lo que sea, cuando usa márgenes negativos todo parece funcionar correctamente, una vista invade el cuadro delimitador de vistas de otra y, dependiendo de cómo se declare en el diseño, estará por encima o por debajo de la otra vista.

También soy consciente de que desde API 21 podemos configurar los atributos translationZy elevationpara que la vista aparezca por encima o por debajo de otras vistas, pero mi preocupación proviene básicamente del hecho de que en la documentación de los layout_marginatributos se especifica claramente que los valores de margen deben ser positivos , dejemos yo cito:

Extracto:
especifica espacio adicional en los lados izquierdo, superior, derecho e inferior de esta vista. Este espacio está fuera de los límites de esta vista. Los valores de los márgenes deben ser positivos . Debe ser un valor de dimensión, que es un número de punto flotante agregado con una unidad como "14.5sp". Las unidades disponibles son: px (píxeles), dp (píxeles independientes de la densidad), sp (píxeles escalados según el tamaño de fuente preferido), en (pulgadas), mm (milímetros) ...

En los años transcurridos desde que hice esta pregunta originalmente, no he tenido ningún problema con los márgenes negativos, traté de evitar usarlos tanto como fue posible, pero no encontré ningún problema, por lo que, aunque la documentación dice que, no estoy demasiado preocupado por eso.

Juan Cortés
fuente
1
Sé que las pruebas de espresso no podrán ver el objeto si uno de sus márgenes es negativo ... así que esa es una razón para no usarlas
Tim Boland

Respuestas:

192

En 2010, @RomainGuy (ingeniero principal de Android) declaró que los márgenes negativos tenían un comportamiento no especificado .

En 2011, @RomainGuy declaró que puede usar márgenes negativos en LinearLayoutyRelativeLayout .

En 2016, @RomainGuy declaró que nunca han sido admitidos oficialmente y no serán admitidos porConstraintLayout .

Sin embargo, es fácil evitar esta limitación.

Agregue una vista auxiliar (altura 0dp, ancho restringido al padre) en la parte inferior de su vista base, en la parte inferior agregue el margen que desee.
Luego, coloque su vista debajo de esta, lo que le permitirá tener un margen "negativo" pero sin tener que usar ningún valor negativo no admitido.

CommonsWare
fuente
1
Entonces parece ser algo inofensivo, dejar abierto en caso de que alguien tenga alguna otra idea
Juan Cortés
1
@DrewLeSueur: No haría esa suposición. No tengo ni idea de lo que significaría un relleno negativo.
CommonsWare
1
@CommonsWare, ¿puede decirme si es posible hacer algo como eso "- @ dimen / anyvalue"? Quiero llamar al valor declarado pero negativo. Ayuda.
deadfish
2
@ 100kg: Lo siento, pero eso no es compatible.
CommonsWare
21
Noté que en Android 4.4 KitKat, algo ha cambiado con respecto a los márgenes negativos (en comparación con 4.3; al menos en Asus Nexus 7). Resulta que lo necesita android:clipChildren="false"y android:clipToPadding="false"donde antes no lo hacía, o las cosas se rompen así .
Jonik
18

Espero que esto ayude a alguien. Aquí hay un código de muestra de trabajo que se ConstraintLayoutbasa en la respuesta de @ CommonsWare:

Agregue una vista auxiliar (altura 0dp, ancho restringido al padre) en la parte inferior de su vista base, en la parte inferior agregue el margen que desee. Luego, coloque su vista debajo de esta, lo que le permitirá tener un margen "negativo" pero sin tener que usar ningún valor negativo no admitido.

Código de muestra:

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

Salida:

ingrese la descripción de la imagen aquí

Vikasdeep Singh
fuente
16

En caso de que desee utilizar un margen negativo, establezca suficiente relleno para el contenedor y su clipToPadding en falso y establezca un margen negativo para sus hijos para que no recorte la vista secundaria.

Ali
fuente
4

Puede que haya sido una mala práctica en el pasado, pero con Material Design y sus botones de acción flotantes, parece ser inevitable y obligatorio en muchos casos ahora. Básicamente, cuando tiene dos diseños separados que no puede poner en un solo RelativeLayout porque necesitan un manejo claramente separado (piense en el encabezado y el contenido, por ejemplo), la única forma de superponer el FAB es hacer que sobresalga de uno de esos diseños que utilizan márgenes negativos. Y esto crea problemas adicionales con las áreas en las que se puede hacer clic.

Gábor
fuente
3

Para mí, y con respecto a establecer un margen negativo en un TextView (me doy cuenta de que el OP se refiere a un ViewGroup, pero estaba buscando problemas para establecer márgenes negativos y llegué aquí) ... Encontré un problema con 4.0.3 ( API 15) SOLAMENTE y la configuración de android:layout_marginTopoandroid:layout_marginBottom con un valor negativo como -2dp.

Por alguna razón, TextView no se muestra en absoluto. Parece haber "desaparecido" de la vista (no solo invisible).

Cuando probé esto con las otras 3 versiones de layout_margin, no vi el problema.

Tenga en cuenta que no he probado esto en un dispositivo real, esto está usando un emulador 4.0.3. Esta es la segunda cosa extraña que he encontrado que solo afecta a 4.0.3, por lo que mi nueva regla es siempre probar con un emulador de 4.0.3 :)

Tengo éxito al reducir el margen inferior de un TextView usando el android:lineSpacingExtra="-2dp"que funciona a pesar de que lo tengo android:singleLine="true"(por lo que no habría pensado que el espaciado de línea sería un factor).

GaryAmundson
fuente
1
Encontré un comportamiento similar en un Nexus 4 (que es xhdpi) y 4.2.2. Había un diseño sin relleno, aunque un diseño principal tenía relleno. Había un TextView adentro con marginTop negativo. En 5.0 funcionó bien. En 4.2.2 tanto en el dispositivo como en un emulador para Nexus 4, desaparece. La solución fue mover el relleno al diseño que contenía TextView.
Louielouie
3

No, no debes usar negative margin. en su lugar deberías usar translate. Incluso si el margen negativo funciona en algún momento, cuando cambia el diseño de manera programable, traducir ayudaría. Y la vista no puede desbordar la pantalla cuando usa el margen.

Cheung Sean
fuente
0

Solo supe que era posible durante un período de tiempo bastante corto. Pero no veo ningún problema con eso. Solo tenga en cuenta los tamaños de pantalla y demás para asegurarse de no crear accidentalmente elementos que no deberían aparecer superpuestos en la pantalla. (es decir, el texto encima del texto es probablemente una mala idea).

FoamyGuy
fuente