Come ottenere un margine di sovrapposizione / negativo sul layout dei vincoli?


118

È possibile ottenere un margine negativo sul layout dei vincoli per ottenere la sovrapposizione? Sto cercando di avere un'immagine centrata sul layout e di avere una visualizzazione Testo in modo tale che si sovrapponga a x dp. Ho provato a impostare il valore del margine negativo ma senza fortuna. Sarebbe fantastico se ci fosse un modo per raggiungere questo obiettivo.


Le linee guida possono aiutare, non ho provato.
Eugen Pechanec

Risposte:


214

Chiarimento: la risposta sotto rimane valida, ma voglio chiarire un paio di cose. La soluzione originale posizionerà una vista con un offset de facto negativo rispetto a un'altra vista come indicato e apparirà nel layout come mostrato.

Un'altra soluzione è usare la proprietà translationY come suggerito da Amir Khorsandi qui . Preferisco quella soluzione più semplice con un avvertimento: la traduzione avviene dopo il layout , quindi le viste che sono vincolate alla vista spostata non seguiranno la traduzione.

Ad esempio, il codice XML seguente mostra due TextView immediatamente sotto l'immagine. Ogni vista è vincolata dall'alto verso il basso con la vista che appare immediatamente sopra di essa.

inserisci qui la descrizione dell'immagine

<androidx.constraintlayout.widget.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:tint="#388E3C"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/ic_action_droid" />

    <TextView
        android:id="@+id/sayName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Say my name."
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        app:layout_constraintTop_toBottomOf="@+id/imageView"
        app:layout_constraintEnd_toEndOf="@+id/imageView"
        app:layout_constraintStart_toStartOf="@+id/imageView" />

    <TextView
        android:id="@+id/sayIt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Say it."
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        app:layout_constraintEnd_toEndOf="@+id/sayName"
        app:layout_constraintStart_toStartOf="@+id/sayName"
        app:layout_constraintTop_toBottomOf="@id/sayName" />
</androidx.constraintlayout.widget.ConstraintLayout>

Ora, traduciamo in alto il TextView "Pronuncia il mio nome" 50dpspecificando

android:translationY="-50dp"

Questo produce quanto segue:

inserisci qui la descrizione dell'immagine

Il TextView "Say my name" è stato spostato come previsto, ma il TextView "Say it" non lo ha seguito come ci si potrebbe aspettare. Questo perché la traduzione avviene dopo il layout . Sebbene la vista si sposti dopo il layout, può comunque essere resa cliccabile nella nuova posizione.

Quindi, IMO, vai con translationX e translationY per margini negativi in ConstraintLayout se l'avvertenza sopra non influisce sul tuo layout; altrimenti, vai con il widget dello spazio come descritto di seguito.


Risposta originale

Sebbene non sembri che i margini negativi saranno supportati ConstraintLayout, esiste un modo per ottenere l'effetto utilizzando gli strumenti disponibili e supportati. Ecco un'immagine in cui il titolo dell'immagine è sovrapposto 22dpdalla parte inferiore dell'immagine - effettivamente un -22dpmargine:

inserisci qui la descrizione dell'immagine

Ciò è stato ottenuto utilizzando un Spacewidget con un margine inferiore uguale all'offset desiderato. Il Spacewidget ha quindi la sua parte inferiore vincolata alla parte inferiore del file ImageView. Ora tutto ciò che devi fare è vincolare la parte superiore del TextViewcon il titolo dell'immagine alla parte inferiore del Spacewidget. Il TextViewsarà posizionato nella parte inferiore della Spacevista ignorando il margine che è stato impostato.

Quello che segue è l'XML che realizza questo effetto. Noterò che lo uso Spaceperché è leggero e destinato a questo tipo di utilizzo, ma avrei potuto usarne un altro tipo Viewe renderlo invisibile. (Probabilmente dovrai apportare modifiche, però.) Potresti anche definire a Viewcon margini zero e l'altezza del margine interno che desideri, e vincolare la parte superiore della TextViewparte superiore del riquadro View.

Un altro approccio potrebbe essere quello di sovrapporre il TextViewsopra ImageViewallineando le parti superiori / inferiori / sinistre / destra e apportare le opportune modifiche ai margini / riempimento. Il vantaggio dell'approccio dimostrato di seguito è che è possibile creare un margine negativo senza troppi calcoli. Questo è tutto per dire che ci sono diversi modi per affrontare questo problema.

Aggiornamento: per una rapida discussione e dimostrazione di questa tecnica, vedere il post del blog di Google Developers Medium .

Margine negativo per ConstraintLayoutXML

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/ic_launcher" />

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

    <TextView
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Say my name"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/marginSpacer" />
</android.support.constraint.ConstraintLayout>

Non funziona nel mio caso, ImageViewè centrato sul genitore, TextViewè sovrapposto sopra ImageView. Quindi Spacefa l'errore quando l'app torna dallo sfondo. Penso che 0dp, 0dp crei qualche problema. Che dire del solo uso Guideline.
illusionJJ

In questo modo non può funzionare perché la vista ha vincoli con il genitore.
R4j

Perché ho bisogno di uno spazio? Ho provato senza spazio e ho lo stesso risultato.
kuzdu

@kuzdu il punto qui è che la parte inferiore dello spazio è vincolata nella parte inferiore dell'immagine Visualizza, il margine sposta lo spazio verso l' alto e quindi la parte superiore della visualizzazione del testo è vincolata nella parte inferiore dello spazio che crea questa "mezza sovrapposizione "effetto che stiamo cercando di ottenere. Pubblica una risposta qui se sei riuscito a ottenerla senza spazio in modo che possiamo vedere i vincoli che hai utilizzato nelle tue due visualizzazioni.
Lucas P.

Sei Heisenberg ...
Nahro

62

Un altro modo è usare translationXo in translationYquesto modo:

  <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" 
                android:translationX="25dp"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"/>

funzionerà come android:layout_marginRight="-25dp"


29
Siate consapevoli di questo, poiché la posizione effettiva della vista rimane nella posizione originale (prima della traduzione), verrà tradotta solo visivamente. In tal modo, gli eventi onClick verranno attivati ​​solo dalla vecchia posizione.
goemic

L'affermazione di @ goemic sembra essere sbagliata, poiché questa non è un'animazione di interpolazione ma un'animazione di proprietà. (per favore correggimi se sbaglio)
Henry

cattiva pratica in quanto non supporta i layout RTL
Salam El-Banna il

27

I margini negativi non sono mai stati ufficialmente supportati in RelativeLayout. I margini negativi non saranno supportati in ConstraintLayout.[...]

- Romain Guy l'8 giugno 2016

Segui questi due problemi:

https://code.google.com/p/android/issues/detail?id=212499 https://code.google.com/p/android/issues/detail?id=234866


la loro idea potrebbe essere che con la disposizione dei vincoli non è necessario un margine negativo. Ciò può essere vero se hai tutti gli elementi su un layout. A volte però vuoi raggruppare logicamente elementi come in una striscia di comandi fatta di pulsanti, che ha i suoi vantaggi in termini di riusabilità, chiarezza e incapsulamento. A quel punto il gruppo avrà una forma rettangolare, ed è questa limitazione su quella forma che rende nuovamente utili e necessari i margini negativi.
AndrewBloom,

I margini negativi emulano esattamente lo stesso concetto della linea di base sul testo, essendo il testo una forma complessa all'interno di un contenitore rettangolare
AndrewBloom,

14

Questo è quello che ho capito dopo ore di tentativi di trovare una soluzione.

Consideriamo due immagini, immagine1 e immagine2. L'immagine2 deve essere posizionata sopra l'immagine1 posizionata in basso a destra.

Esempio di viste sovrapposte Immagine

Possiamo usare lo spazio widget per le viste sovrapposte.

Vincola i quattro lati del widget Spazio rispettivamente con i quattro lati dell'immagine1. Per questo esempio, vincola il lato sinistro dell'immagine2 con il lato destro del widget Space e il lato superiore dell'immagine2 con il lato inferiore del widget Space. Questo collegherà l'immagine2 con il widget Space e poiché il widget Space è vincolato da tutti i lati, possiamo definire la polarizzazione orizzontale o verticale richiesta che sposterà l'immagine2 come richiesto.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Player">
 <ImageView
     android:id="@+id/image1"
     android:layout_width="250dp"
     android:layout_height="167dp"
     android:src="@android:color/holo_green_dark"
     app:layout_constraintEnd_toEndOf="parent"
     app:layout_constraintStart_toStartOf="parent"
     app:layout_constraintTop_toTopOf="parent" />
 <Space
     android:id="@+id/space"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     app:layout_constraintBottom_toBottomOf="@+id/image1"
     app:layout_constraintEnd_toEndOf="@+id/image1"
     app:layout_constraintHorizontal_bias="0.82"
     app:layout_constraintStart_toStartOf="@+id/image1"
     app:layout_constraintTop_toTopOf="@+id/image1"
     app:layout_constraintVertical_bias="0.62" />
 <ImageView
     android:id="@+id/image2"
     android:layout_width="82dp"
     android:layout_height="108dp"
     android:src="@android:color/holo_green_light"
     app:layout_constraintStart_toEndOf="@+id/space"
     app:layout_constraintTop_toBottomOf="@+id/space" />
 </android.support.constraint.ConstraintLayout>

Inoltre, per posizionare image2 al centro in basso di image1, possiamo vincolare i lati sinistro e destro di image2 rispettivamente con i lati sinistro e destro del widget Space. Allo stesso modo, possiamo posizionare image2 ovunque modificando i vincoli di image2 con il widget Space.


Grazie per la risposta!
user3193413

11

Ho trovato un modo per farlo molto più semplice.

Fondamentalmente hai ImageView, quindi sulla visualizzazione del testo aggiungi il vincolo superiore per abbinare il vincolo superiore dell'immagine e aggiungi semplicemente il margine superiore del TextView in modo che corrisponda per ottenere il comportamento del tipo di margine -ve.


9
a meno che l'altezza dell'immagine non sia variabile
Stas Shusha

Funzionerebbe ancora. Dovresti solo fare attenzione a dove desideri che il tuo widget superiore si sovrapponga all'immagine, l'impostazione del margine da destra o dal basso potrebbe essere un'opzione migliore, oppure potresti usare il bias, che risponde alla domanda .
Gabriel Vasconcelos

4

Questo aiuterà molti

Nel mio caso voglio il mio design in questo modo:

dopo

Significa che voglio che la mia immagine sia visualizzata per metà della loro larghezza, quindi fondamentalmente ho bisogno di un margine negativo della metà della larghezza effettiva dell'immagine, ma l'intero layout nel layout dei vincoli e nel layout dei vincoli non consente il margine negativo, quindi ho ottenuto questo con il codice sottostante

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:scaleType="centerCrop"
        android:src="@drawable/ic_launcher_background"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/guideline"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="50dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

In modo che ImageView finisca all'inizio della linea guida. e l'effetto è lo stesso del margine negativo all'inizio di 50dp.

E anche se la larghezza della tua vista non è fissa ed è in percentuale in modo da poter posizionare la linea guida con la percentuale e ottenere qualsiasi effetto tu voglia

Codifica felice :)


0

Devi solo usare il widget Space nel tuo layout

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<Space
    android:id="@+id/negative_margin"
    android:layout_width="16dp"
    android:layout_height="16dp"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintRight_toLeftOf="parent"/>

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Widget who needs negative margin"
    app:layout_constraintTop_toBottomOf="@+id/negative_margin"
    app:layout_constraintLeft_toLeftOf="@+id/negative_margin" />


0

Questa è una vecchia domanda ma molto posta, il modo più veloce per ottenere ciò è vincolare la parte superiore e inferiore al lato della vista a cui vuoi ancorarti, in questo modo:

        <androidx.appcompat.widget.AppCompatImageView
        android:layout_width="55dp"
        android:layout_height="55dp"
        app:layout_constraintBottom_toBottomOf="@+id/parent_view_id"
        app:layout_constraintTop_toBottomOf="@+id/parent_view_id"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent" />

Questo lo centrerà nella linea inferiore della vista, centrata orizzontalmente.


-1

Un modo semplice.

Non sono sicuro il modo migliore.

Basta avvolgere usando LinearLayout

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
 <View
 android:layout_width="wrap_content"
 android:layout_marginLeft="-20dp"
 android:layout_height="wrap_content"/>
</LinearLayout>

Questo aggiunge un po 'più di annidamento, MA funziona per animare le viste dall'alto, a differenza delle altre soluzioni qui, che presumono che la vista sarà completamente mostrata. Grazie!
Leo supporta Monica Cellio il

2
Questa risposta richiede molte più informazioni. Non è chiaro come inserire qualcosa in un LinearLayout possa essere utilizzato per realizzare la sovrapposizione.
Robert Liberatore
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.