157 votes

Comment obtenir un chevauchement/une marge négative dans le cadre d'une mise en page par contrainte ?

Est-il possible d'obtenir une marge négative sur la disposition des contraintes pour obtenir un chevauchement ? J'essaie d'avoir une image centrée sur la mise en page et d'avoir une vue Texte telle qu'elle chevauche un par x dp. J'ai essayé de définir une valeur de marge négative, mais sans succès. Ce serait formidable s'il y avait un moyen d'y parvenir.

1 votes

Ligne directrice peut aider, je n'ai pas essayé.

287voto

Cheticamp Points 22529

Mise à jour ConstraintLayout prend désormais en charge les marges négatives avec la version 2.1.0-alpha2. Il suffit d'indiquer

android:layout_marginTop="-25dp"

pour une marge négative de 25dp. (Et ils disaient que ce n'était pas possible !)



Clarification : La réponse ci-dessous reste valable, mais je tiens à clarifier certaines choses. La solution originale place une vue avec un de facto un décalage négatif par rapport à une autre vue comme indiqué et apparaîtra dans la mise en page comme indiqué.

Une autre solution consiste à utiliser le traductionY propriété comme suggéré par Amir Khorsandi aquí . Je préfère cette solution, plus simple, à une réserve près : la traduction se produit post-layout Ainsi, les vues qui sont contraintes à la vue déplacée ne suivront pas la translation.

Par exemple, le XML suivant affiche deux TextViews immédiatement sous l'image. Chaque vue est contrainte de haut en bas avec la vue qui apparaît immédiatement au-dessus d'elle.

enter image description here

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

Maintenant, traduisons le "Dis mon nom" TextView par 50dp en précisant

android:translationY="-50dp"

Cela donne le résultat suivant :

enter image description here

Le "Dis mon nom" TextView s'est déplacé vers le haut comme prévu, mais le "Say it" TextView n'y a pas donné suite comme on pourrait s'y attendre. Cela est dû au fait que la traduction se produit post-layout . Bien que la vue se déplace après la mise en page, il est toujours possible de la rendre cliquable dans sa nouvelle position.

Donc, IMO, allez avec traductionX y traductionY pour les marges négatives dans ConstraintLayout si l'avertissement ci-dessus n'affecte pas votre mise en page ; sinon, optez pour le format espace comme indiqué ci-dessous.

Une autre mise en garde : Comme l'a déclaré Salam El-Banna dans un commentaire à une autre réponse, traductionX ne sera pas une bonne solution pour les mises en page RTL puisque le signe de la traduction dictera la direction du décalage (gauche/droite) indépendamment de la nature RTL ou LTR de la mise en page.


Réponse originale

Bien qu'il ne semble pas que les marges négatives soient prises en charge dans le cadre de l'initiative de l'Union européenne en matière d'éducation. ConstraintLayout Si l'on ne veut pas que le titre de l'image se chevauche, il est possible d'obtenir cet effet à l'aide des outils disponibles et pris en charge. Voici une image où le titre de l'image se chevauche 22dp à partir du bas de l'image - en fait un -22dp marge :

enter image description here

Pour ce faire, on a utilisé un Space avec une marge inférieure égale au décalage que vous souhaitez. Le site Space Le bas du widget est alors contraint au bas de l'objet ImageView . Maintenant, tout ce que vous avez à faire est de contraindre le haut du TextView avec le titre de l'image au bas de la page Space widget. Le site TextView sera positionné en bas de l'écran Space ignorant la marge qui a été définie.

Voici le XML qui permet d'obtenir cet effet. Je noterai que j'utilise Space parce qu'il est léger et prévu pour ce type d'utilisation, mais j'aurais pu utiliser un autre type de View et l'a rendu invisible. (Vous aurez probablement besoin de faire des ajustements, cependant.) Vous pourriez également définir une fonction View avec des marges nulles et la hauteur de la marge d'insertion que vous souhaitez, et contraindre le haut de l'élément TextView en haut de l'encart View .

Une autre approche encore consisterait à superposer les TextView sur le dessus de la ImageView en alignant le haut et le bas, la gauche et la droite, et en ajustant les marges et l'interlignage. L'avantage de l'approche démontrée ci-dessous est qu'une marge négative peut être créée sans beaucoup de calculs. Tout cela pour dire qu'il existe plusieurs façons d'aborder la question.

Mise à jour : Pour une discussion rapide et une démonstration de cette technique, voir le média des développeurs Google article de blog .

Marge négative pour ConstraintLayout XML

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

0 votes

Cela ne fonctionne pas dans mon cas, ImageView est centré sur le parent, TextView est un chevauchement au-dessus ImageView . Ensuite, Space fait l'erreur quand l'application revient de l'arrière-plan. Je pense que 0dp, 0dp cause des problèmes. Et si vous utilisiez simplement Guideline .

0 votes

Cette méthode ne peut pas fonctionner si la vue a des contraintes avec le parent.

0 votes

Pourquoi ai-je besoin d'un espace ? J'ai essayé sans espace et j'ai le même résultat.

85voto

Amir Khorsandi Points 608

Une autre façon est d'utiliser translationX o translationY comme ça :

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

cela fonctionnera comme android:layout_marginRight="-25dp"

48 votes

Soyez conscient de ceci, puisque la position réelle de la vue reste à la position originale (avant la traduction), elle sera traduite seulement visuellement. Ainsi, les événements onClick ne seront déclenchés qu'à partir de l'ancienne position.

0 votes

La déclaration d'@goemic semble être erronée, puisqu'il ne s'agit pas d'une animation tween mais d'une animation de propriété. (merci de me corriger si je me trompe)

3 votes

Mauvaise pratique car il ne prend pas en charge les mises en page RTL

28voto

Eugen Pechanec Points 342

Les marges négatives n'ont jamais été officiellement prises en charge dans RelativeLayout. Les marges négatives ne seront pas prises en charge dans ConstraintLayout. [...]

-- Romain Guy le 8 juin 2016

Suivez ces deux questions :

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

1 votes

Leur idée est peut-être qu'avec le constraintlayout vous n'avez pas besoin de marge négative. Cela peut être vrai si vous avez tous les éléments sur une seule mise en page. Mais parfois, on souhaite regrouper logiquement des éléments, comme dans une bande de commande composée de boutons, ce qui présente ses propres avantages en termes de réutilisation, de clarté et d'encapsulation. Dans ce cas, le groupe aura une forme rectangulaire, et c'est cette limitation de la forme qui rend les marges négatives à nouveau utiles et nécessaires.

0 votes

Les marges négatives reproduisent exactement le même concept que la ligne de base du texte, le texte étant une forme complexe dans un conteneur rectangulaire.

25voto

Swati Navalkar Points 61

C'est ce que j'ai découvert après avoir passé des heures à essayer de trouver une solution.

Considérons deux images, image1 et image2. L'image2 doit être placée au-dessus de l'image1 positionnée en bas à droite.

Exemple de vues superposées image

Nous pouvons utiliser Espace widget pour les vues superposées.

Contrainte les quatre côtés du widget Espace avec les quatre côtés de l'image1 respectivement. Dans cet exemple, contraignez le côté gauche de l'image2 avec le côté droit du widget Espace et le côté supérieur de l'image2 avec le côté inférieur du widget Espace. L'image2 sera ainsi liée au widget Espace et, puisque le widget Espace est contraint de tous les côtés, nous pouvons définir les biais horizontaux ou verticaux nécessaires pour déplacer l'image2 selon les besoins.

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

De plus, pour positionner l'image 2 au centre et en bas de l'image 1, nous pouvons contraindre les côtés gauche et droit de l'image 2 avec les côtés gauche et droit du widget Espace respectivement. De même, nous pouvons placer l'image2 n'importe où en modifiant les contraintes de l'image2 avec le widget Space.

12voto

bond Points 561

J'ai trouvé un moyen de le faire beaucoup plus simplement.

En fait, il faut avoir l'ImageView, puis ajouter une contrainte supérieure à la vue texte pour qu'elle corresponde à la contrainte supérieure de l'image et ajouter la marge supérieure de la vue texte pour qu'elle corresponde au comportement de type marge -ve.

11 votes

Sauf si la hauteur de l'image est variable

0 votes

Ça peut toujours marcher. Vous devrez juste faire attention à l'endroit où vous souhaitez que votre widget supérieur recouvre l'image, définir la marge à partir de la droite ou du bas pourrait être une meilleure option, ou vous pourriez utiliser le biais, qui répondent tous à la question.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X