Почему гравитация не работает применительно к Относительной компоновке?
Я уже понимаю, что если я использую layout_gravity="center_horizontal"
в текстовом представлении текст будет в центре. Но я не хочу использовать это, потому что я хочу иметь как можно меньше кода, и лучший способ сделать это - применить gravity="center_horizontal"
на мой относительный макет. Я также задаю этот вопрос, потому что я обеспокоен даже использованием gravity
или же layout_gravity
с относительными раскладками вообще. Как и во время моего исследования, я наткнулся на этот ответ.
Обратите внимание на часть, которая говорит:
Не используйте gravity/layout_gravity с RelativeLayout. Используйте их для представлений в LinearLayouts и FrameLayouts.
Хотя это кажется мне довольно очевидным из относительной компоновки Android-документации, которая четко перечисляет gravity
В качестве действительного атрибута Google предполагал, что эти атрибуты будут использоваться с относительными макетами.
Если эта цитата верна, как мне центрировать виды в относительных макетах?
Также вот мой код:
Обратите внимание, что заголовок расположен не по центру
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:gravity="center_horizontal"
tools:context="com.something">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textAlignment="center"
android:text="@string/app_title"
android:layout_marginBottom="@dimen/main_spacing"
android:textSize="24sp" />
<AutoCompleteTextView
android:id="@+id/enterContact"
android:text="Enter Contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:layout_below="@+id/title"
android:layout_marginBottom="@dimen/main_spacing" />
</RelativeLayout>
6 ответов
Это дополнительный ответ на Gravity и layout_gravity на Android.
Посмотреть gravity
а также layout_gravity
внутри относительной компоновки
Мое оригинальное утверждение, что gravity
а также layout_gravity
не должны использоваться в подпредставлениях RelativeLayout
был частично неправ gravity
на самом деле работает нормально. Тем не мение, layout_gravity
не имеет никакого эффекта Это можно увидеть в примере ниже. Светло-зеленый и светло-синий - это TextViews. Два других цвета фона - это RelativeLayouts.
Как вы видете, gravity
работает, но layout_gravity
не работает
Относительная компоновка с gravity
Мой оригинальный ответ о gravity
а также layout_gravity
имели дело с этими атрибутами, применяемыми к представлениям в ViewGroup
(конкретно LinearLayout
), а не к ViewGroup
сам. Тем не менее, можно установить gravity
а также layout_gravity
на RelativeLayout
, layout_gravity
будет влиять на то, как RelativeLayout
позиционируется внутри своего родителя, поэтому я не буду иметь дело с этим здесь. Как gravity
влияет на подпредставления, хотя, показано на рисунке ниже.
Я изменил ширину всех подпредставлений, чтобы происходящее стало более понятным. Обратите внимание, что путь RelativeLayout
Ручки гравитации - это взять все подпредставления как группу и переместить их по макету. Это означает, что какой бы ни был самый широкий вид, будет определять, как все остальное позиционируется. Таким образом, гравитация в относительном макете, вероятно, полезна, только если все подпредставления имеют одинаковую ширину.
Линейный макет с gravity
Когда вы добавляете gravity
к LinearLayout
, он организует подпредставления, как и следовало ожидать. Например, можно "сохранить код", установив gravity
из LinearLayout
в center_horizontally
, Таким образом, нет необходимости индивидуально устанавливать layout_gravity
каждого подпредставления. Смотрите различные варианты на изображении ниже.
Обратите внимание, что когда представление использует layout_gravity
, он отменяет гравитацию LinearLayout. (Это можно увидеть в заголовке для двух макетов на левом изображении. The LinearLayout gravity
был установлен на left
а также right
но название TextView's layout_gravity
был установлен на center_horizontally
.)
Финальные заметки
При позиционировании представлений в RelativeLayout общий способ сделать это - добавить в каждое представление что-то вроде следующего:
layout_alignParentTop
layout_centerVertical
layout_below
layout_toRightOf
Если кто-то хочет установить все представления одновременно, LinearLayout
вероятно, будет лучше (или, возможно, используя стиль).
Итак, чтобы подвести итог,
-
layout_gravity
не работает для подпредставлений в RelativeLayout. -
gravity
RelativeLayout работает, но не так, как можно было бы ожидать.
Дополнительный XML
XML для изображения "Просмотр gravity
а также layout_gravity
внутри Относительного Макета ":
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#e3e2ad" >
<TextView
android:id="@+id/tvTop1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="24sp"
android:text="Views' gravity=" />
<!-- examples of gravity -->
<TextView
android:id="@+id/tvTop2"
android:layout_below="@id/tvTop1"
android:layout_width="200dp"
android:layout_height="40dp"
android:background="#bcf5b1"
android:gravity="left"
android:text="left" />
<TextView
android:id="@+id/tvTop3"
android:layout_below="@id/tvTop2"
android:layout_width="200dp"
android:layout_height="40dp"
android:background="#aacaff"
android:gravity="center_horizontal"
android:text="center_horizontal" />
<TextView
android:id="@+id/tvTop4"
android:layout_below="@id/tvTop3"
android:layout_width="200dp"
android:layout_height="40dp"
android:background="#bcf5b1"
android:gravity="right"
android:text="right" />
<TextView
android:id="@+id/tvTop5"
android:layout_below="@id/tvTop4"
android:layout_width="200dp"
android:layout_height="40dp"
android:background="#aacaff"
android:gravity="center"
android:text="center" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#d6c6cd" >
<TextView
android:id="@+id/tvBottom1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="24sp"
android:text="Views' layout_gravity=" />
<!-- examples of layout_gravity -->
<TextView
android:id="@+id/tvBottom2"
android:layout_below="@id/tvBottom1"
android:layout_width="200dp"
android:layout_height="40dp"
android:layout_gravity="left"
android:background="#bcf5b1"
android:text="left" />
<TextView
android:id="@+id/tvBottom3"
android:layout_below="@id/tvBottom2"
android:layout_width="200dp"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:background="#aacaff"
android:text="center_horizontal" />
<TextView
android:id="@+id/tvBottom4"
android:layout_below="@id/tvBottom3"
android:layout_width="200dp"
android:layout_height="40dp"
android:layout_gravity="right"
android:background="#bcf5b1"
android:text="right" />
<TextView
android:id="@+id/tvBottom5"
android:layout_below="@id/tvBottom4"
android:layout_width="200dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:background="#aacaff"
android:text="center" />
</RelativeLayout>
</LinearLayout>
XML для изображения "Относительная компоновка с гравитацией":
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_horizontal"
android:background="#e3e2ad" >
<TextView
android:id="@+id/tvTop1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:text="Views' gravity=" />
<!-- examples of gravity -->
<TextView
android:id="@+id/tvTop2"
android:layout_below="@id/tvTop1"
android:layout_width="200dp"
android:layout_height="40dp"
android:background="#bcf5b1"
android:gravity="left"
android:text="left" />
<TextView
android:id="@+id/tvTop3"
android:layout_below="@id/tvTop2"
android:layout_width="300dp"
android:layout_height="40dp"
android:background="#aacaff"
android:gravity="center_horizontal"
android:text="center_horizontal" />
<TextView
android:id="@+id/tvTop4"
android:layout_below="@id/tvTop3"
android:layout_width="100dp"
android:layout_height="40dp"
android:background="#bcf5b1"
android:gravity="right"
android:text="right" />
<TextView
android:id="@+id/tvTop5"
android:layout_below="@id/tvTop4"
android:layout_width="150dp"
android:layout_height="40dp"
android:background="#aacaff"
android:gravity="center"
android:text="center" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:background="#d6c6cd" >
<TextView
android:id="@+id/tvBottom1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:text="Views' gravity=" />
<!-- examples of layout_gravity -->
<TextView
android:id="@+id/tvBottom2"
android:layout_below="@id/tvBottom1"
android:layout_width="200dp"
android:layout_height="40dp"
android:gravity="left"
android:background="#bcf5b1"
android:text="left" />
<TextView
android:id="@+id/tvBottom3"
android:layout_below="@id/tvBottom2"
android:layout_width="300dp"
android:layout_height="40dp"
android:gravity="center_horizontal"
android:background="#aacaff"
android:text="center_horizontal" />
<TextView
android:id="@+id/tvBottom4"
android:layout_below="@id/tvBottom3"
android:layout_width="100dp"
android:layout_height="40dp"
android:gravity="right"
android:background="#bcf5b1"
android:text="right" />
<TextView
android:id="@+id/tvBottom5"
android:layout_below="@id/tvBottom4"
android:layout_width="150dp"
android:layout_height="40dp"
android:gravity="center"
android:background="#aacaff"
android:text="center" />
</RelativeLayout>
</LinearLayout>
XML для изображения "Линейный макет с гравитацией":
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_horizontal"
android:background="#e3e2ad"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="24sp"
android:text="View's gravity=" />
<TextView
android:layout_width="200dp"
android:layout_height="40dp"
android:background="#bcf5b1"
android:gravity="left"
android:text="left" />
<TextView
android:layout_width="300dp"
android:layout_height="40dp"
android:background="#aacaff"
android:gravity="center_horizontal"
android:text="center_horizontal" />
<TextView
android:layout_width="100dp"
android:layout_height="40dp"
android:background="#bcf5b1"
android:gravity="right"
android:text="right" />
<TextView
android:layout_width="150dp"
android:layout_height="40dp"
android:background="#aacaff"
android:gravity="center"
android:text="center" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:background="#d6c6cd"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="24sp"
android:text="View's gravity=" />
<TextView
android:layout_width="200dp"
android:layout_height="40dp"
android:background="#bcf5b1"
android:gravity="left"
android:text="left" />
<TextView
android:layout_width="300dp"
android:layout_height="40dp"
android:background="#aacaff"
android:gravity="center_horizontal"
android:text="center_horizontal" />
<TextView
android:layout_width="100dp"
android:layout_height="40dp"
android:background="#bcf5b1"
android:gravity="right"
android:text="right" />
<TextView
android:layout_width="150dp"
android:layout_height="40dp"
android:background="#aacaff"
android:gravity="center"
android:text="center" />
</LinearLayout>
</LinearLayout>
TlDr: android:gravity Работает с RelativeLayout, вы можете перейти к нижней части, если вы не хотите читать объяснение
РЕДАКТИРОВАТЬ это гигантская стена текста, пожалуйста, потерпите меня
Это то, чего я хочу достичь:
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textAlignment="center"
android:text="@string/app_title"
android:layout_marginBottom="@dimen/main_spacing"
android:textSize="24sp"
android:layout_centerHorizontal="true"/> <!-- LAYOUT PARAMS WORK!!!-->
Почему это работает, в то время как android:gravity
(видимо) нет?
если ваша цель - поместить TextView в горизонтальный центр макета / экрана, вы должны позволить
RelativeLayout
знать!это достигается через то, что называется
LayoutParams
- это структуры данных, определяемые каждымView
которые используются родителем представления (в этом случае RelativeLayout)так скажем, ваш
TextView
имеет следующееLayoutParams
:андроид:layout_centerHorizontal="истина"
вы получите что-то вроде этого:
Когда RelativeLayout
распределяет свои дочерние представления по экрану, в то время как выполняется метод обратного вызова - onLayout (...) - который является частью более сложной последовательности методов, которая будет определять положение каждого дочернего представления внутри RelativeLayout, это достигается частично путем доступа к LayoutParams
в каждом ребенке View
в этом случае эта строка в вашем TextView
- Вот почему мы говорим, что LayoutParams передаются родителю, как в ссылке, которую вы упомянули ранее
ВНИМАНИЕ: Бесконечный источник путаницы!
Посмотреть расположение внутри Layout
с / ViewGroup
S делается через LayoutParam
с onLayout
звонки
Так получилось, что некоторые макеты вроде FrameLayout
иметь LayoutParam под названием Android: layout_gravity, который вызывает большую путаницу с android:gravity
свойство, которое может определить каждое представление, которое НЕ то же самое и даже не LayoutParam
android:gravity
используется любым видом (например, TextView
например) разместить его содержимое внутри.
Пример: допустим, что вы изменили свой TextView, чтобы он был очень высоким, и вы хотите, чтобы текст был внизу TextView, а не вверху
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="95dp" <------------ very high!
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textAlignment="center"
android:text="@string/app_title"
android:layout_marginBottom="@dimen/main_spacing"
android:textSize="24sp"
android:layout_centerHorizontal="true" <----- LayoutParams for RelativeLayout
/>
TextView центрируется в RelativeLayout, но текст находится в верхнейчасти "окна"
Давайте использовать Android: гравитация для управления положениемтекстаВНУТРИTextView
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="95dp"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textAlignment="center"
android:text="@string/app_title"
android:layout_marginBottom="@dimen/main_spacing"
android:textSize="24sp"
android:layout_centerHorizontal="true"
android:gravity="bottom" <---**NOT LayoutParams**, NOT passed to RLayout
/>
Результат: как и ожидалось, изменилась тольковнутренняя часть вида
TLDR Теперь, если вы хотите игнорировать все вышеперечисленное и по-прежнему использовать Android: гравитация с RelativeLayout,RelativeLayout
также View
поэтому у него есть свойство android: gravity, но вы должны удалить другие свойства или LayoutParams, которые будут переопределять поведение, определенное свойством android: gravity, смотреть на android: gravity при работе с RelativeLayout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:gravity="bottom"> <!-- NOT LAYOUT PARAMS -->
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="95dp"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textAlignment="center"
android:text="@string/app_title"
android:layout_marginBottom="@dimen/main_spacing"
android:textSize="24sp"
android:layout_centerHorizontal="true"
/>
<AutoCompleteTextView
android:id="@+id/enterContact"
android:text="Enter Contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:layout_below="@+id/title"
android:layout_marginBottom="@dimen/main_spacing" />
</RelativeLayout>
У меня всегда были проблемы с RelativeLayouts и TextViews. Я думаю, что это связано с тем, что TextView рассчитывает его размер динамически, и это мешает ему хорошо работать с гравитацией макета. Это только одно мое предположение. Решение, которое я обычно принимаю, заключается в настройке горизонтального размера textview с помощью match_parent. Это может быть неоптимальным решением, но оно должно работать. В случае, если вам нужен textView с фиксированным размером, вы можете поместить размер с фиксированным размером, и он тоже должен работать, это создает проблемы только с wrap_content.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:gravity="center_horizontal"
tools:context="com.something">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textAlignment="center"
android:text="@string/app_title"
android:layout_marginBottom="@dimen/main_spacing"
android:textSize="24sp" />
</RelativeLayout>
Изменить: как предложено @Valentino S., добавив
android:layout_centerHorizontal="true"
с wrap_content тоже должно работать. Причина в моей голове все та же: размер textView вычисляется позже.
Как сказано в документации:
Android: гравитация
Определяет, как объект должен располагать свое содержимое по осям X и Y в пределах своих собственных границ.
...
center_horizontal
Поместите объект в горизонтальный центр его контейнера, не меняя его размера.
Итак android:gravity="center_horizontal"
отцентрирует горизонтальное расположение RelativeLayout к его родителю. Не делая его центр контента горизонтальным.
Помни что android:layout_gravity
используется для самого представления относительно родителя или макета.
Помните, что поведение Layout может незначительно отличаться для каждого уровня API. И обратите внимание, что мы не можем на 100% быть уверены, что визуальный результат в Layout Editor правильный. Всегда проверяйте свой макет на реальных устройствах.
Тестирование вашего макета, для меня это работает (TextView
по центру правильно).
Тем не менее, вы также можете удалить android:gravity="center_horizontal"
от RelativeLayout
и добавить android:layout_centerHorizontal="true"
в TextView
,
Попробуй это:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:background="#000000"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:background="#ffffffff"
android:text="TITLE"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textSize="24sp" />
<AutoCompleteTextView
android:id="@+id/enterContact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/title"
android:layout_marginBottom="10dp"
android:background="#ffffffff"
android:text="Enter Contact"
android:textAlignment="center" />
</RelativeLayout>