Constraint Layout에서 오버랩 / 네거티브 마진을 얻는 방법은 무엇입니까?


118

겹침을 달성하기 위해 제약 레이아웃에서 마이너스 마진을 달성 할 수 있습니까? 레이아웃 중앙에 이미지를 배치하고 x dp와 겹치도록 텍스트보기를 사용하려고합니다. 마이너스 마진 값을 설정하려고 시도했지만 운이 없습니다. 이것을 달성하는 방법이 있다면 좋을 것입니다.


지침 이 도움이 될 수 있지만 시도하지 않았습니다.
Eugen Pechanec

답변:


214

설명 : 아래 답변은 유효하지만 몇 가지를 명확히하고 싶습니다. 원래 솔루션은 명시된대로 다른 뷰에 대해 사실상 음의 오프셋으로 뷰를 배치하고 표시된대로 레이아웃에 나타납니다.

또 다른 해결책은 여기에서 Amir Khorsandi가 제안한 translationY 속성 을 사용하는 입니다. 저는이 솔루션을 한 가지주의 사항으로 더 간단하게 선호합니다. 번역은 레이아웃 후 발생 하므로 변위 된 뷰로 제한되는 뷰는 번역을 따르지 않습니다.

예를 들어 다음 XML 은 이미지 바로 아래에 두 개의 TextView를 표시합니다 . 각보기는 바로 위에 표시되는보기와 함께 위에서 아래로 제한됩니다.

여기에 이미지 설명 입력

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

이제 "Say my name" TextView 를 다음 50dp을 지정하여 번역 해 보겠습니다.

android:translationY="-50dp"

그러면 다음이 생성됩니다.

여기에 이미지 설명 입력

"Say my name" TextView 가 예상대로 위로 이동했지만 "Say it" TextView 가 예상대로 따라 오지 않았습니다. 이는 번역이 레이아웃 이후에 발생하기 때문 입니다. 뷰가 레이아웃 후 이동하더라도 새 위치에서 클릭 할 수 있습니다.

따라서 IMO 는 위의주의 사항이 레이아웃에 영향을주지 않는 경우 ConstraintLayout의 음수 여백에 대해 translationXtranslationY 를 사용 합니다. 그렇지 않으면 아래에 설명 된대로 스페이스 위젯을 사용하십시오 .


원래 답변

에서 음수 여백이 지원되는 것 같지는 않지만 ConstraintLayout사용 가능하고 지원되는 도구를 사용하여 효과를 얻을 수있는 방법이 있습니다. 다음은 이미지 제목이 이미지 22dp하단에서 겹치는 이미지입니다. 사실상 -22dp여백입니다.

여기에 이미지 설명 입력

이는 Space원하는 오프셋과 동일한 하단 여백이 있는 위젯을 사용하여 수행되었습니다 . 그러면 Space위젯의 하단이 ImageView. 이제해야 할 일은 TextView이미지 제목이있는 상단을 Space위젯 하단으로 제한하는 것 입니다. 이 TextView의 바닥에 위치한다 Space설정된 마진을 무시보기.

다음은이 효과를 달성하는 XML입니다. 내가 사용하는 것이주의 할 것이다 Space그것이 가볍고 사용이 유형의 목적이기 때문에,하지만 난 다른 유형을 사용할 수도 View그것은 눈에 보이지 않는했다. (하지만 조정이 필요할 수 있습니다.) View여백이 0이고 원하는 인세 트 여백의 높이로 a 를 정의하고 TextView의 상단을 삽입의 상단으로 제한 할 수도 있습니다 View.

또 다른 접근 방식은 상단 / 하단 / 왼쪽 / 오른쪽을 정렬 TextView하여 상단 을 오버레이하고 ImageView여백 / 패딩을 적절하게 조정하는 것입니다. 아래 설명 된 접근 방식의 이점은 많은 계산없이 음의 마진을 생성 할 수 있다는 것입니다. 이것에 접근하는 방법에는 여러 가지가 있습니다.

업데이트 : 이 기술에 대한 빠른 토론 및 데모는 Google Developers Medium 블로그 게시물을 참조하십시오 .

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>

내 경우에는 작동하지 않고 ImageView부모 중심에 있으며 TextView위에 겹칩니다 ImageView. 그런 다음 Space앱이 백그라운드에서 돌아올 때 오류가 발생합니다. 0dp, 0dp가 문제가 있다고 생각합니다. 그냥 Guideline.
illusionJJ

이 방법은 부모와의 제약이있는 뷰에 대해 작동하지 않습니다.
R4j

왜 스페이스가 필요한가요? 나는 공간없이 시도했고 동일한 결과를 얻었습니다.
kuzdu

@kuzdu 여기서 요점은 공간의 하단이 imageView의 하단에 제한되고 여백이 공간을 위로 이동 한 다음 텍스트보기 의 상단 이 공간 의 하단 에 제한 되어이 "반 오버레이"를 생성한다는 것입니다. "우리가 달성하려는 효과. 두 개의 뷰에서 사용한 제약을 볼 수 있도록 공백없이 얻은 경우 여기에 답변을 게시하십시오.
Lucas P.

당신은 Heisenberg ...
Nahro

62

또 다른 방법은 사용하고 translationX또는 translationY다음과 같이 :

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

그것은 같이 작동 할 것입니다 android:layout_marginRight="-25dp"


29
뷰의 실제 위치는 원래 위치 (번역 전)에 유지되므로 시각적으로 만 번역됩니다. 따라서 onClick 이벤트는 이전 위치 내에서만 트리거됩니다.
goemic

@goemic의 진술은 트윈 애니메이션이 아니라 속성 애니메이션이기 때문에 잘못된 것 같습니다. (만약 내가 잘못 나 수정하시기 바랍니다)
헨리

RTL 레이아웃을 지원하지 않기 때문에 나쁜 습관
Salam El-Banna

27

음수 여백은 RelativeLayout에서 공식적으로 지원되지 않습니다. ConstraintLayout에서는 음수 여백이 지원되지 않습니다. [...]

-Romain Guy, 2016 년 6 월 8 일

다음 두 가지 문제를 따르십시오.

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


그들의 생각은 constraintlayout을 사용하면 음의 여백이 필요하지 않다는 것입니다. 하나의 레이아웃에 모든 요소가있는 경우 해당 될 수 있습니다. 때로는 버튼으로 구성된 명령 스트립과 같이 논리적으로 요소를 그룹화하고 싶지만 재사용 가능성과 명확성 및 캡슐화에 대한 자체 장점이 있습니다. 그 시점에서 그룹은 직사각형 모양을 갖게되며, 음의 여백을 유용하고 다시 필요하게 만드는 것은 그 모양에 대한 이러한 제한입니다.
AndrewBloom

네거티브 여백은 텍스트의 기준선과 정확히 동일한 개념을 모방하며 직사각형 컨테이너 내의 복잡한 모양의 텍스트입니다.
AndrewBloom

14

이것은 해결책을 찾으려고 몇 시간 후에 알아 낸 것입니다.

image1과 image2의 두 이미지를 고려해 보겠습니다. Image2는 오른쪽 하단에 위치한 image1 위에 배치됩니다.

겹치는 뷰 예 영상

겹치는 뷰에 Space 위젯을 사용할 수 있습니다.

공간 위젯의 네면을 각각 image1의 네면으로 제한합니다. 이 예제에서는 image2의 왼쪽을 Space 위젯의 오른쪽으로 제한하고 image2의 위쪽을 Space 위젯의 아래쪽으로 제한합니다. 이렇게하면 image2가 Space 위젯과 연결되고 Space 위젯은 모든 측면에서 제한되므로 필요에 따라 image2를 이동하는 필수 수평 또는 수직 편향을 정의 할 수 있습니다.

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

또한 image1의 중앙 하단에 image2를 배치하기 위해 Space 위젯의 왼쪽과 오른쪽을 각각 사용하여 image2의 왼쪽과 오른쪽을 제한 할 수 있습니다. 마찬가지로 Space 위젯으로 image2의 제약 조건을 변경하여 image2를 어디에 든 배치 할 수 있습니다.


답변 감사합니다!
user3193413

11

훨씬 더 간단한 방법을 찾았습니다.

기본적으로 ImageView가있는 다음 Text View에서 이미지의 상단 제약 조건과 일치하도록 상단 제약 조건을 추가하고 -ve 여백 유형 동작을 달성하기 위해 일치하는 TextView의 여백 상단을 추가합니다.


9
상고 가변 아니라면
스타스 슈샤

여전히 작동합니다. 상단 위젯이 이미지를 오버레이 할 위치에주의해야합니다. 오른쪽 또는 하단에서 여백을 설정하는 것이 더 나은 옵션이 될 수 있습니다. 또는 편견을 사용할 수 있습니다. 모든 질문에 답할 수 있습니다. .
Gabriel Vasconcelos

4

이것은 많은 것을 도울 것입니다

제 경우에는 다음과 같은 디자인을 원합니다.

후

내 이미지가 너비의 절반을 표시하므로 기본적으로 실제 이미지 너비의 절반의 음수 여백이 필요하지만 제약 레이아웃 및 제약 레이아웃의 전체 레이아웃은 음수 여백을 허용하지 않으므로 아래 코드로 이것을 달성했습니다.

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

따라서 ImageView는 지침의 시작 부분에서 끝납니다. 효과는 50dp 시작 부분의 음수 여백과 같습니다.

또한 뷰의 너비가 고정되지 않고 백분율로 표시되어 백분율로 가이드 라인을 배치하고 원하는 효과를 얻을 수있는 경우

해피 코딩 :)


0

레이아웃에서 Space 위젯 만 사용하면됩니다.

<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

이것은 오래된 질문이지만 많은 질문을 받았습니다.이를 달성하는 가장 빠른 방법은 고정하려는 뷰의 측면에 상단과 하단을 제한하는 것입니다.

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

이렇게하면 뷰의 하단 라인 중앙에 수평으로 중앙에 배치됩니다.


-1

간단한 방법.

최선의 방법을 모르겠습니다.

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>

이것은 좀 더 중첩을 추가하지만, 뷰가 완전히 표시 될 것이라고 가정하는 여기의 다른 솔루션과 달리 위에서부터 뷰를 애니메이션하는 데 작동합니다. 감사!
레오 모니카 Cellio 지원

2
이 답변에는 더 많은 정보가 필요합니다. LinearLayout에 무언가를 넣는 것이 오버랩을 달성하는 데 어떻게 사용될 수 있는지 명확하지 않습니다.
Robert Liberatore
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.