É uma má prática usar margens negativas no Android?

114

Demonstração de margem negativa:

                         insira a descrição da imagem aqui

O cenário

Sobrepor as visualizações definindo uma margem negativa para uma delas de modo que invada a caixa delimitadora de outra visualização.

Pensamentos

Parece que funciona da maneira que você esperaria, com a sobreposição dos layouts, se necessário. Mas não quero ter um problema maior por não saber fazer as coisas direito. Emuladores, dispositivos físicos, o que você quiser, quando você usa margens negativas tudo parece funcionar corretamente, uma visão invade a caixa delimitadora de outras visões e dependendo de como está declarado no layout ficará acima ou abaixo da outra visão.

Também estou ciente de que, desde a API 21, podemos definir os atributos translationZe elevationpara fazer a exibição aparecer acima ou abaixo de outras exibições, mas minha preocupação vem basicamente do fato de que na documentação dos layout_marginatributos está claramente especificado que os valores de margem devem ser positivos , vamos citação de mim:

Trecho:
especifica espaço extra nos lados esquerdo, superior, direito e inferior desta vista. Este espaço está fora dos limites desta vista. Os valores da margem devem ser positivos . Deve ser um valor de dimensão, que é um número de ponto flutuante anexado a uma unidade como "14,5 sp". As unidades disponíveis são: px (pixels), dp (pixels independentes da densidade), sp (pixels redimensionados com base no tamanho de fonte preferido), em (polegadas), mm (milímetros) ...

Nos anos desde que fiz essa pergunta originalmente, não tive problemas com margens negativas, tentei evitar usá-las o máximo possível, mas não encontrei nenhum problema, portanto, embora a documentação afirme que, eu também não preocupado com isso.

Juan Cortés
fonte
1
Eu sei que os testes de café expresso não conseguirão ver o objeto se uma de suas margens for negativa ... então essa é uma razão para não usá-los
Tim Boland

Respostas:

192

Em 2010, @RomainGuy (engenheiro principal do Android) afirmou que as margens negativas tinham comportamento não especificado .

Em 2011, @RomainGuy afirmou que você pode usar margens negativas em LinearLayouteRelativeLayout .

Em 2016, @RomainGuy afirmou que nunca foi oficialmente suportado e não será suportado porConstraintLayout .

No entanto, é fácil contornar essa limitação.

Adicione uma visualização auxiliar (altura 0 dp, largura restrita ao pai) na parte inferior de sua visualização de base e, na parte inferior, adicione a margem desejada.
Em seguida, posicione sua visualização abaixo desta, efetivamente permitindo que ela tenha uma margem "negativa", mas sem ter que usar qualquer valor negativo não suportado.

CommonsWare
fonte
1
Parece ser uma coisa inofensiva então, deixando em aberto caso alguém tenha alguma outra visão
Juan Cortés
1
@DrewLeSueur: Eu não faria essa suposição. Não tenho ideia do que significaria um preenchimento negativo.
CommonsWare
1
@CommonsWare você pode me dizer, é possível fazer algo assim `- @ dimen / anyvalue"? Eu quero chamar o valor declarado, mas negativo. Ajuda.
deadfish
2
@ 100kg: Desculpe, mas isso não é compatível.
CommonsWare
21
Notei que no Android 4.4 KitKat, algo mudou com relação às margens negativas (em comparação com 4.3; pelo menos no Asus Nexus 7). Acontece que você precisa android:clipChildren="false"e android:clipToPadding="false"onde antes não precisava, ou coisas quebram assim .
Jonik
18

Espero que isso ajude alguém. Aqui está um exemplo de código de trabalho usando com ConstraintLayoutbase na resposta de @ CommonsWare:

Adicione uma visualização auxiliar (altura 0 dp, largura restrita ao pai) na parte inferior de sua visualização de base e, na parte inferior, adicione a margem desejada. Em seguida, posicione sua visualização abaixo desta, efetivamente permitindo que ela tenha uma margem "negativa", mas sem ter que usar qualquer valor negativo não suportado.

Código de amostra:

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

Resultado:

insira a descrição da imagem aqui

Vikasdeep Singh
fonte
16

Caso você queira usar margem negativa, defina preenchimento suficiente para o container e seu clipToPadding como false e defina a margem negativa para seus filhos para que não corte a exibição dos filhos!

Todos
fonte
4

Pode ter sido uma prática ruim no passado, mas com o Material Design e seus botões de ação flutuantes, parece ser inevitável e necessário em muitos casos agora. Basicamente, quando você tem dois layouts separados que não podem ser colocados em um único RelativeLayout porque eles precisam de um tratamento distinto (pense no cabeçalho e no conteúdo, por exemplo), a única maneira de sobrepor o FAB é fazê-lo sobressair de um daqueles layouts usando margens negativas. E isso cria problemas adicionais com áreas clicáveis.

Gábor
fonte
3

Para mim, e em relação à configuração de uma margem negativa em um TextView (eu percebo que o OP está se referindo a um ViewGroup, mas eu estava procurando problemas com a configuração de margens negativas e cheguei aqui) ... Encontrei um problema com 4.0.3 ( API 15) SOMENTE e a configuração de android:layout_marginTopou android:layout_marginBottompara um valor negativo, como -2dp.

Por algum motivo, o TextView não é exibido. Parece ter "desaparecido" da vista (não apenas invisível).

Quando tentei fazer isso com as outras 3 versões do layout_margin, não vi o problema.

Observe que eu não tentei isso em um dispositivo real, estou usando um emulador 4.0.3. Esta é a segunda coisa estranha que descobri que afetou apenas a 4.0.3, então minha nova regra é sempre testar com um emulador 4.0.3 :)

Tenho sucesso com a redução da margem inferior de um TextView usando o android:lineSpacingExtra="-2dp"que funciona mesmo que eu tenha android:singleLine="true"(e então eu não teria pensado que o espaçamento entre linhas seria um fator).

GaryAmundson
fonte
1
Eu encontrei um comportamento semelhante em um Nexus 4 (que é xhdpi) e 4.2.2. Havia um layout sem preenchimento, embora um layout pai tivesse preenchimento. Havia um TextView dentro com marginTop negativo. No 5.0 funcionou bem. Em 4.2.2 no dispositivo e em um emulador para Nexus 4, ele desaparece. A solução foi mover o preenchimento para o layout que continha o TextView.
louielouie
3

Não, você não deve usar negative margin. em vez disso, você deve usar translate. Mesmo que a margem negativa funcione em algum momento, ao alterar o layout de maneira programável, a tradução ajudará. E a visualização não pode ultrapassar a tela quando você usa a margem.

Cheung Sean
fonte
0

Eu só sabia que isso era possível por um curto período de tempo. Mas não vejo problema nisso. Esteja ciente dos tamanhos de tela e outros, para ter certeza de não criar itens que não deveriam aparecer sobrepostos na tela acidentalmente. (ou seja, texto acima do texto é provavelmente uma má ideia.)

FoamyGuy
fonte