Wie kann eine Überlappung / ein negativer Rand beim Einschränkungslayout erzielt werden?

116

Ist es möglich, einen negativen Spielraum beim Einschränkungslayout zu erzielen, um eine Überlappung zu erzielen? Ich versuche, ein Bild auf dem Layout zu zentrieren und eine Textansicht zu haben, die a um x dp überlappt. Ich habe versucht, einen negativen Margin-Wert einzustellen, aber kein Glück. Es wäre großartig, wenn es einen Weg gäbe, dies zu erreichen.

Bindung
quelle
Richtlinie kann helfen, ich habe es nicht versucht.
Eugen Pechanec

Antworten:

213

Klarstellung: Die folgende Antwort bleibt gültig, aber ich möchte ein paar Dinge klarstellen. Die ursprüngliche Lösung platziert eine Ansicht mit einem de facto negativen Versatz in Bezug auf eine andere Ansicht wie angegeben und wird wie gezeigt im Layout angezeigt.

Eine andere Lösung besteht darin, die von Amir Khorsandi hier vorgeschlagene translationY- Eigenschaft zu verwenden . Ich bevorzuge diese Lösung als einfacher mit einer Einschränkung: Die Übersetzung erfolgt nach dem Layout , sodass Ansichten, die auf die verschobene Ansicht beschränkt sind, nicht der Übersetzung folgen.

In der folgenden XML- Datei werden beispielsweise zwei Textansichten direkt unter dem Bild angezeigt . Jede Ansicht ist von oben nach unten eingeschränkt, wobei die Ansicht unmittelbar darüber angezeigt wird.

Geben Sie hier die Bildbeschreibung ein

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

Nun lassen Sie uns das „Say my name“ übersetzen Textview , indem 50dpdurch die Angabe

android:translationY="-50dp"

Dies ergibt Folgendes:

Geben Sie hier die Bildbeschreibung ein

Die Textansicht "Sag meinen Namen" hat sich wie erwartet verschoben, aber die Textansicht "Sag es" hat sie nicht wie erwartet weiterverfolgt . Dies liegt daran, dass die Übersetzung nach dem Layout erfolgt . Obwohl die Ansicht nach dem Layout verschoben wird, kann sie an der neuen Position weiterhin anklickbar gemacht werden.

Also, IMO, wählen Sie in ConstraintLayout für negative Ränder translationX und translationY, wenn die oben genannten Einschränkungen Ihr Layout nicht beeinflussen. Andernfalls verwenden Sie das unten beschriebene Leerzeichen- Widget.


Ursprüngliche Antwort

Obwohl es nicht den Anschein hat, dass negative Ränder unterstützt werden ConstraintLayout, gibt es eine Möglichkeit, den Effekt mithilfe der verfügbaren und unterstützten Tools zu erzielen. Hier ist ein Bild, bei dem sich der Bildtitel 22dpvom unteren Bildrand überlappt - praktisch ein -22dpRand:

Geben Sie hier die Bildbeschreibung ein

Dies wurde erreicht, indem ein SpaceWidget mit einem unteren Rand verwendet wurde, der dem gewünschten Versatz entspricht. Das SpaceWidget hat dann seinen unteren Rand auf den unteren Rand des Widgets beschränkt ImageView. Jetzt müssen Sie nur noch den oberen TextViewRand des Bildtitels auf den unteren Rand des SpaceWidgets beschränken. Das TextViewwird am unteren Rand der SpaceAnsicht positioniert, wobei der festgelegte Rand ignoriert wird.

Das Folgende ist das XML, das diesen Effekt erzielt. Ich werde bemerken, dass ich benutze, Spaceweil es leicht ist und für diese Art der Verwendung vorgesehen ist, aber ich hätte eine andere Art von verwenden Viewund es unsichtbar machen können. (Wahrscheinlich müssen Sie jedoch Anpassungen vornehmen.) Sie können auch einen ViewRand mit Null und die Höhe des gewünschten Einschubrandes definieren und den oberen Rand TextViewauf den oberen Rand des Einschubs beschränken View.

Ein weiterer Ansatz wäre, die TextViewOberseite zu überlagern, ImageViewindem oben / unten / links / rechts ausgerichtet und geeignete Anpassungen an Rändern / Polstern vorgenommen werden. Der Vorteil des unten gezeigten Ansatzes besteht darin, dass eine negative Marge ohne viel Rechenaufwand erstellt werden kann. Das heißt, es gibt verschiedene Möglichkeiten, dies zu erreichen.

Update: Eine kurze Diskussion und Demo dieser Technik finden Sie im Blogbeitrag von Google Developers Medium .

Negative Margin für 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>
Cheticamp
quelle
Funktioniert in meinem Fall nicht, ImageViewist auf den Elternteil zentriert, TextViewüberlappt sich oben ImageView. Dann Spacemacht der Fehler, wenn App aus dem Hintergrund zurück. Ich denke 0dp, 0dp macht einige Probleme. Was ist mit nur verwenden Guideline.
IllusionJJ
Diese Methode kann nicht für die Ansicht verwendet werden, hat Einschränkungen mit dem übergeordneten Element.
R4j
Warum brauche ich ein Leerzeichen? Ich habe es ohne Platz versucht und ich habe das gleiche Ergebnis.
Kuzdu
@kuzdu der Punkt hier ist , dass der Boden des Raumes an der Unterseite des Imageview begrenzt ist, bewegt sich der Rand den Raum, und dann die Spitze der Textansicht ist an dem beschränkten Boden des Raumes , die diesen „halb überlagernde schafft "Effekt, den wir erreichen wollen. Bitte posten Sie hier eine Antwort, wenn Sie es geschafft haben, sie ohne Leerzeichen zu erhalten, damit wir die Einschränkungen sehen können, die Sie für Ihre beiden Ansichten verwendet haben.
Lucas P.
Du bist Heisenberg ...
Nahro
62

Ein anderer Weg ist translationXoder translationYso:

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

es wird so funktionieren android:layout_marginRight="-25dp"

Amir Khorsandi
quelle
28
Beachten Sie dies, da die tatsächliche Position der Ansicht (vor der Übersetzung) an der ursprünglichen Position bleibt und nur visuell übersetzt wird. Dabei werden onClick-Ereignisse nur von der alten Position aus ausgelöst.
goemic
Die Aussage von @ goemic scheint falsch zu sein, da dies keine Tween-Animation, sondern eine Eigenschaftsanimation ist. (Bitte korrigieren Sie mich, wenn ich falsch liege)
Henry
schlechte Praxis, da es keine RTL-Layouts unterstützt
Salam El-Banna
26

Negative Margen wurden in RelativeLayout noch nie offiziell unterstützt. Negative Ränder werden in ConstraintLayout nicht unterstützt. [...]

- Romain Guy am 8. Juni 2016

Befolgen Sie diese beiden Punkte:

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

Eugen Pechanec
quelle
Ihre Idee könnte sein, dass Sie mit Constraintlayout keine negative Marge benötigen. Dies kann zutreffen, wenn Sie alle Elemente in einem Layout haben. Manchmal möchten Sie jedoch logische Elemente wie in einer Befehlsleiste aus Schaltflächen gruppieren, was seine eigenen Vorteile hinsichtlich Wiederverwendbarkeit, Klarheit und Kapselung hat. Zu diesem Zeitpunkt hat die Gruppe eine rechteckige Form, und diese Einschränkung dieser Form macht negative Ränder wieder nützlich und notwendig.
AndrewBloom
Negative Ränder emulieren genau das gleiche Konzept der Grundlinie auf Text, wobei Text eine komplexe Form in einem rechteckigen Container darstellt
AndrewBloom
14

Dies habe ich herausgefunden, nachdem ich stundenlang versucht hatte, eine Lösung zu finden.

Betrachten wir zwei Bilder, Bild1 und Bild2. Bild2 ist oben rechts auf Bild1 zu platzieren.

Beispiel für überlappende Ansichten Bild

Wir können das Space- Widget für überlappende Ansichten verwenden.

Beschränken Sie die vier Seiten des Space-Widgets auf die vier Seiten des Bildes1. In diesem Beispiel beschränken Sie die linke Seite von image2 auf die rechte Seite des Space-Widgets und die Oberseite von image2 auf die untere Seite des Space-Widgets. Dadurch wird image2 mit dem Space-Widget verknüpft. Da das Space-Widget von allen Seiten eingeschränkt ist, können Sie die erforderliche horizontale oder vertikale Vorspannung definieren, die image2 nach Bedarf verschiebt.

<?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>

Um Bild2 in der Mitte unten in Bild1 zu positionieren, können Sie außerdem die linke und rechte Seite von Bild2 mit der linken bzw. rechten Seite des Space-Widgets einschränken. Ebenso können wir image2 an einer beliebigen Stelle platzieren, indem wir die Einschränkungen von image2 mit dem Space-Widget ändern.

Swati Navalkar
quelle
Danke für die Antwort!
user3193413
11

Ich habe einen Weg gefunden, es viel einfacher zu machen.

Lassen Sie die ImageView im Grunde genommen die oberste Einschränkung in der Textansicht hinzufügen, um sie an die oberste Einschränkung des Bildes anzupassen, und fügen Sie einfach den oberen Rand der Textansicht hinzu, um das Verhalten des Randtyps -ve zu erreichen.

Bindung
quelle
9
es sei denn, die Bildhöhe ist variabel
Stas Shusha
Es würde immer noch funktionieren. Sie müssen nur vorsichtig sein, wo Ihr oberes Widget das Bild überlagern soll. Das Festlegen des Randes von rechts oder unten könnte eine bessere Option sein, oder Sie könnten Voreingenommenheit verwenden, die alle die Frage beantworten .
Gabriel Vasconcelos
4

Dies wird vielen helfen

In meinem Fall möchte ich mein Design so:

nach dem

Das heißt, ich möchte, dass mein Bild die Hälfte ihrer Breite anzeigt, daher benötige ich im Grunde genommen einen negativen Rand der Hälfte der tatsächlichen Bildbreite, aber mein gesamtes Layout im Einschränkungslayout und im Einschränkungslayout erlaubt keinen negativen Rand, also habe ich dies mit dem folgenden Code erreicht

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

Damit ImageView am Anfang der Richtlinie endet. und der Effekt ist der gleiche wie bei einer negativen Marge zu Beginn von 50 dp.

Und auch, wenn die Breite Ihrer Ansicht nicht festgelegt und in Prozent angegeben ist, sodass Sie die Richtlinie mit dem Prozentsatz platzieren und den gewünschten Effekt erzielen können

Viel Spaß beim Codieren :)

Vijay Makwana
quelle
0

Sie müssen nur das Space-Widget in Ihrem Layout verwenden

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

Hagar Magdy
quelle
0

Dies ist eine alte Frage, die jedoch sehr häufig gestellt wird. Der schnellste Weg, dies zu erreichen, besteht darin, die Ober- und Unterseite auf die Seite der Ansicht zu beschränken, an der Sie verankern möchten.

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

Dadurch wird es in der unteren Zeile der Ansicht horizontal zentriert zentriert.

Ahmed Awad
quelle
-1

Ein einfacher Weg.

Ich bin mir nicht sicher, wie ich es am besten machen soll.

Einfach mit LinearLayout einwickeln

<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>
최봉재
quelle
Dies fügt etwas mehr Verschachtelung hinzu, ABER es funktioniert zum Animieren von Ansichten von oben, im Gegensatz zu den anderen Lösungen hier, bei denen davon ausgegangen wird, dass die Ansicht vollständig angezeigt wird. Vielen Dank!
Leo unterstützt Monica Cellio
2
Diese Antwort benötigt viel mehr Informationen. Unklar, wie etwas in ein LinearLayout eingefügt werden kann, um eine Überlappung zu erreichen.
Robert Liberatore