Использование отрицательных полей в Android - плохая практика?


115

Демо отрицательной маржи:

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

Сценарий

Перекрытие представлений путем установки отрицательного поля для одного из них, чтобы оно вторгалось в ограничивающую рамку другого представления.

мысли

Кажется, это работает так, как вы ожидаете, с перекрытием макетов, если они должны. Но я не хочу столкнуться с более серьезной проблемой из-за того, что по незнанию не все делаю правильно. Эмуляторы, физические устройства, вы называете это, когда вы используете отрицательные поля, кажется, что все работает правильно, одно представление вторгается в ограничивающую рамку другого представления и в зависимости от того, как оно объявлено в макете, оно будет выше или ниже другого представления.

Я также знаю , что с API 21 мы можем установить translationZи elevation атрибуты , чтобы сделать вид появляется выше или ниже другие взгляды , но мое беспокойство в основном исходит из того , что в документации для layout_marginатрибутов это явно указано , что значения маржи должны быть положительными , пусть я цитирую:

Отрывок:
указывает дополнительное пространство слева, сверху, справа и снизу этого вида. Это пространство находится за пределами этого представления. Значения маржи должны быть положительными . Должно быть значение измерения, представляющее собой число с плавающей запятой, к которому добавляется единица измерения, например «14,5 sp». Доступные единицы: px (пиксели), dp (пиксели, не зависящие от плотности), sp (масштабированные пиксели на основе предпочтительного размера шрифта), in (дюймы), мм (миллиметры) ...

За годы, прошедшие с тех пор, как я задал этот вопрос, у меня не было проблем с отрицательными полями, я старался избегать их использования в максимально возможной степени, но не сталкивался с какими-либо проблемами, поэтому, хотя в документации указано, что я не слишком беспокоился об этом.


1
я знаю, что тесты эспрессо не смогут увидеть объект, если одно из его полей отрицательное ... так что это причина не использовать их
Тим Боланд

Ответы:


194

В 2010 году @RomainGuy (основной разработчик Android) заявил, что отрицательные поля имеют неопределенное поведение .

В 2011 году @RomainGuy заявил, что вы можете использовать отрицательные поля для LinearLayoutиRelativeLayout .

В 2016 году @RomainGuy заявил, что они никогда официально не поддерживались и не будут поддерживатьсяConstraintLayout .

Однако это ограничение легко обойти.

Добавьте вспомогательное представление (высота 0dp, ширина ограничена родительским) внизу вашего базового вида, внизу добавьте желаемый маржа.
Затем разместите свое представление под этим, что позволит ему иметь «отрицательный» запас, но без использования каких-либо неподдерживаемых отрицательных значений.


1
В таком случае кажется, что это безобидная вещь, оставляя открытой на случай, если у кого-то появятся другие идеи
Хуан Кортес

1
@DrewLeSueur: Я бы не стал делать этого предположения. Я понятия не имею, что может означать отрицательная прокладка.
CommonsWare

1
@CommonsWare, можете ли вы сказать мне, возможно ли сделать что-то подобное `- @ dimen / anyvalue"? Я хочу вызвать объявленное значение, но отрицательное. Помогите.
deadfish

2
@ 100 кг: Извините, но это не поддерживается.
CommonsWare

21
Я заметил, что в Android 4.4 KitKat что-то изменилось в отношении отрицательных полей (по сравнению с 4.3; по крайней мере, на Asus Nexus 7). Оказывается, вам нужно android:clipChildren="false"и android:clipToPadding="false"там, где раньше не было, иначе все сломается .
Jonik 06

18

Надеюсь, это кому-то поможет. Вот рабочий пример кода, ConstraintLayoutоснованный на ответе @ CommonsWare:

Добавьте вспомогательное представление (высота 0dp, ширина ограничена родительским) внизу вашего базового вида, внизу добавьте желаемый маржа. Затем разместите свое представление под этим, что позволит ему иметь «отрицательный» запас, но без использования каких-либо неподдерживаемых отрицательных значений.

Образец кода:

<TextView
    android:id="@+id/below"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#F1B36D"
    android:padding="30dp"
    android:text="I'm below"
    android:textColor="#ffffff"
    android:textSize="48sp"
    android:textAlignment="center"
    tools:layout_editor_absoluteX="129dp"
    tools:layout_editor_absoluteY="0dp" />

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

<TextView
    android:id="@+id/top"
    android:layout_width="100dp"
    android:layout_height="60dp"
    android:textAlignment="center"
    android:textColor="#ffffff"
    android:text="I'M ON TOP!"
    android:background="#676563"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/space" />

Вывод:

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


16

Если вы хотите использовать отрицательное поле, установите для контейнера и его clipToPadding значение false и установите отрицательное поле для его дочерних элементов, чтобы он не обрезал дочернее представление!


4

В прошлом это могло быть плохой практикой, но с материальным дизайном и его плавающими кнопками действий это кажется неизбежным и необходимым во многих случаях сейчас. По сути, когда у вас есть два отдельных макета, которые вы не можете поместить в один RelativeLayout, потому что они нуждаются в отдельной обработке (например, заголовок и содержимое), единственный способ перекрыть FAB - заставить его выступать из одного макеты с отрицательными полями. И это создает дополнительные проблемы с интерактивными областями.


3

Для меня и относительно установки отрицательного поля для TextView (я понимаю, что OP относится к ViewGroup, но я искал проблемы с установкой отрицательных полей, и я приземлился здесь) ... Я обнаружил проблему с 4.0.3 ( API 15) ТОЛЬКО и установка android:layout_marginTopили android:layout_marginBottomна отрицательное значение, например -2dp.

По какой-то причине TextView вообще не отображается. Кажется, что он "ушел" из поля зрения (а не просто невидим).

Когда я попробовал это с другими 3 версиями layout_margin, я не увидел проблемы.

Обратите внимание, что я не пробовал это на реальном устройстве, здесь используется эмулятор 4.0.3. Это вторая странная вещь, которая затронула только 4.0.3, поэтому мое новое правило - всегда тестировать с эмулятором 4.0.3 :)

Мне удалось уменьшить нижнее поле TextView, используя android:lineSpacingExtra="-2dp"которое работает, хотя у меня есть android:singleLine="true"(и поэтому я бы не подумал, что межстрочный интервал будет фактором).


1
Я обнаружил похожее поведение на Nexus 4 (это xhdpi) и 4.2.2. Был макет без отступов, хотя у родительского макета было отступ. Внутри был TextView с отрицательным значением marginTop. На 5.0 нормально работало. На 4.2.2 как на устройстве, так и в эмуляторе для Nexus 4 пропадает. Решением было переместить отступ в макет, содержащий TextView.
louielouie

3

Нет, использовать не следует negative margin. вместо этого вы должны использовать translate. Даже если отрицательная маржа иногда срабатывает, когда вы меняете макет программно, перевод поможет. И просмотр не может выходить за пределы экрана, если вы используете маржу.


0

Я знал только, что это было возможно на довольно короткий период времени. Но я не вижу в этом проблем. Просто помните о размерах экрана и тому подобном, чтобы случайно не сделать элементы, которые не должны перекрываться на экране. (т.е. текст поверх текста - плохая идея.)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.