Як домогтися перекриття / негативної межі на макеті обмежень?


118

Чи можна домогтися негативної маржі на макеті обмежень для досягнення перекриття? Я намагаюсь, щоб зображення було зосереджене на макеті та було перегляд тексту таким чином, щоб воно перекривалося на x dp. Я спробував встановити від’ємне значення маржі, але не пощастило. Було б чудово, якщо є спосіб досягти цього.


Настанова може допомогти, я не намагався.
Євген Печанець

Відповіді:


214

Уточнення: Відповідь, що надається нижче, залишається вірною, але я хочу уточнити пару речей. Оригінальне рішення розмістить подання з фактично негативним зміщенням стосовно іншого виду, як зазначено, і відобразиться у макеті, як показано.

Іншим рішенням є використання властивості translation Y, як тут запропонував Амір Хорсанді . Я вважаю за краще, щоб це рішення було простішим з одним застереженням: Переклад відбувається після макетування , тому перегляди, обмежені переглядом переміщених, не перейдуть за перекладом.

Наприклад, наступний 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>

Тепер, давайте переводити «Скажи моє ім'я» TextView вгору 50dp, вказавши

android:translationY="-50dp"

Це призводить до наступного:

введіть тут опис зображення

TextView "Скажи моє ім'я" змістився вгору, як очікувалося, але TextView "Скажи це" не дотримувався цього, як ми могли очікувати. Це відбувається тому, що переклад відбувається після макета . Незважаючи на те, що подання переміщується після макета, його все одно можна зробити натисканням у новому положенні.

Отже, IMO, перейдіть з translationX та translationY на негативні поля в ConstraintLayout, якщо попередній застереження не впливає на ваш макет; в іншому випадку перейдіть з віджетом пробілу, як зазначено нижче.


Оригінальна відповідь

Хоча не видається, що негативні маржі будуть підтримуватися в ConstraintLayout, є спосіб досягти ефекту за допомогою доступних та підтримуваних інструментів. Ось зображення, де назва зображення перекривається 22dpзнизу зображення - фактично -22dpполем:

введіть тут опис зображення

Це було досягнуто за допомогою Spaceвіджета з нижньою межею, що дорівнює бажаному зміщенню. Потім Spaceвіджет обмежений донизу ImageView. Тепер все, що вам потрібно зробити, - це обмежити верхню частину TextViewз заголовком зображення до нижньої частини Spaceвіджета. TextViewБуде розташований в нижній частині Spaceзору , ігноруючи запас , який був встановлений.

Далі йде XML, що забезпечує цей ефект. Зауважу, що я використовую, Spaceоскільки він легкий і призначений для такого типу використання, але я міг би використовувати інший тип Viewі зробив його невидимим. (Мабуть, вам, можливо, доведеться вносити корективи.) Ви також можете визначити Viewнульові поля та висоту потрібного поля вставки та обмежити верхню частину 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робить помилку, коли App повертається з фону. Я думаю, що 0dp, 0dp створює деякі проблеми. Що про просто використання Guideline.
illusionJJ

Цей спосіб не може працювати для перегляду, який має обмеження для батьків.
R4j

Навіщо мені потрібен пробіл? Я спробував без місця і маю той самий результат.
кузду

@kuzdu суть тут у тому, що дно пробілу обмежено внизу imageView, поле переміщує простір вгору, а потім верх текстового перегляду обмежується внизу простору, що створює цю "половину накладання "ефекту, який ми намагаємося досягти. Будь ласка, опублікуйте відповідь тут, якщо вам вдалося отримати її без пробілу, щоб ми могли побачити обмеження, які ви використали у ваших двох переглядах.
Лукас П.

Ти Гейзенберг ...
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
Салам Ель-Банна

27

Негативні маржі ніколи не були офіційно підтримувані в RelativeLayout. Негативні поля не підтримуватимуться у ConstraintLayout. [...]

- Ромен Гай 8 червня 2016 року

Дотримуйтесь цих двох питань:

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


їхня ідея може полягати в тому, що при обмеженні розміщення вам не потрібна негативна маржа. Це може бути правдою, якщо у вас є всі елементи на одному макеті. Іноді хоч ви хочете згрупувати логічно елементи, наприклад, у командній смужці з кнопок, яка має свої переваги щодо повторного використання та чіткості та інкапсуляції. Після цього група матиме прямокутну форму, і саме це обмеження на цю форму робить негативні поля знову корисними та необхідними.
AndrewBloom

Негативні поля імітують саме таку концепцію базової лінії щодо тексту, що представляє собою текст складної форми у прямокутному контейнері
AndrewBloom

14

Це я зрозумів після годин спроб знайти рішення.

Розглянемо два зображення, зображення1 та зображення2. Зображення2 розміщується вгорі зображення1, розташованому праворуч внизу.

Приклад перекриття переглядів зображення

Ми можемо використовувати Космос віджет для перекриття подань.

Обмежте чотири сторони віджета Space на чотири сторони зображення1 відповідно. У цьому прикладі обмежте ліву частину зображення2 правою стороною віджета 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>

Крім того, для розміщення image2 в нижній частині зображення1 ми можемо обмежити ліву та праву сторони image2 лівою та правою сторонами віджета Space відповідно. Так само ми можемо розмістити image2 в будь-якому місці, змінивши обмеження image2 за допомогою віджету Space.


Дякую за відповідь!
користувач3193413

11

Я знайшов спосіб зробити це набагато простіше.

В основному є ImageView, а потім у Text View додайте верхнє обмеження для відповідності верхньому обмеженню зображення та просто додайте верхній край TextView, щоб він відповідав досягненню поведінки типу -ve margin.


9
якщо висота зображення не змінюється
Стас Шуша

Це все одно спрацювало б. Вам просто потрібно бути обережними, де ви хочете, щоб ваш верхній віджет наклав зображення, встановлення поля праворуч або знизу може бути кращим варіантом, або ви можете використовувати упередження, які відповідають на питання .
Габріель Васконцелос

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>

Це додає трохи більше гніздування, але це працює для анімації поглядів зверху, на відміну від інших тут рішень, які передбачають, що Вид буде показаний повністю. Дякую!
Лео підтримує Моніку Селліо

2
Ця відповідь потребує набагато більше інформації. Незрозуміло, як розміщення чогось у LinearLayout може бути використане для перекриття.
Роберт Лібераторе
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.