Почему гравитация не применяется при относительной компоновке?

Я уже понимаю, что если я использую layout_gravity="center_horizontal" в текстовом представлении, тогда текст будет центром. Но я не хочу использовать это, потому что я хочу иметь как можно меньше кода, и лучший способ сделать это – применить gravity="center_horizontal" к моей относительной компоновке. Я также задаю этот вопрос, потому что меня беспокоит даже использование gravity или layout_gravity с относительными макетами вообще. Как и при выполнении моих исследований, я пришел к такому ответу.

Обратите внимание на часть, которая гласит:

Не используйте гравитацию / layout_gravity с RelativeLayout. Используйте их для видов в LinearLayouts и FrameLayouts.

Несмотря на то, что мне кажется довольно очевидным относительный формат Android Documentation , в котором четко указано, что 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> 

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

Это дополнительный ответ на 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 , она упорядочивает LinearLayout , как и следовало ожидать. Например, можно было бы «сохранить код», установив gravity LinearLayout на center_horizontally . Таким образом, нет необходимости индивидуально устанавливать layout_gravity для каждого поднабора. См. Различные варианты на изображении ниже.

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

Обратите внимание, что когда view использует layout_gravity , он переопределяет гравитацию LinearLayout. (Это можно увидеть в заголовке для двух макетов в левом изображении. Сила LinearLayout была установлена left и right , но название layout_gravity TextView было установлено в center_horizontally .)

Окончательные примечания

При позиционировании представлений в RelativeLayout общий способ сделать это – добавить к каждому виду следующие вещи:

  • layout_alignParentTop
  • layout_centerVertical
  • layout_below
  • layout_toRightOf

Если вы хотите сразу установить все виды, LinearLayout , вероятно, будет лучше (или, возможно, с использованием стиля).

Итак, чтобы подвести итог,

  • layout_gravity не работает для subviews в 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> 

Тестирование макета, для меня он работает ( TextView центрирован правильно).

Однако вы также можете удалить android:gravity="center_horizontal" из RelativeLayout и добавить android:layout_centerHorizontal="true" в TextView .

У меня всегда были проблемы с RelativeLayouts и TextViews. Я думаю, что это связано с тем, что TextView вычисляет его размер динамически, и это не позволяет ему хорошо работать с гравитацией макета. Это только одно мое предположение. Решение, которое я обычно принимаю, заключается в настройке горизонтального размера textview с помощью match_parent. Это может быть субоптимальное решение, но оно должно работать. Если вам нужен текстовый файл с фиксированным размером, вы можете поместить фиксированный размер и работать тоже, он дает проблемы только с 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" будет android:gravity="center_horizontal" горизонтальное положение RelativeLayout до его родителя. Не сделать его контент-центр горизонтальным.

Помните, что android:layout_gravity используется для самого представления относительно родителя или макета.

Помните, что поведение макета может немного отличаться для каждого уровня API. Следует отметить, что мы не можем на 100% убедиться, что визуальный результат в редакторе макета правильный. Всегда проверяйте свой макет в реальных устройствах.

попробуй это:

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

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

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 (по- видимому ) нет?

  1. Если ваша цель – разместить TextView в горизонтальном центре Layout / Screen, вы должны сообщить RelativeLayout !

  2. Это достигается через то, что называется LayoutParams – это структуры данных, определенные каждым View которые используются родителем View (в данном случае RelativeLayout)

  3. Так что скажем, у вашего TextView есть следующие LayoutParams :

    андроид: layout_centerHorizontal = "истина"

Вы получите что-то вроде этого:

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

Когда RelativeLayout распространяет свои дочерние представления по экрану, по способу запускается метод обратного вызова – onLayout (…) – который является частью более сложной последовательности методов, которая будет определять положение каждого дочернего элемента. Просмотр внутри RelativeLayout , это достигается частично за счет доступа к LayoutParams в каждом дочернем View , в этом случае эта строка в вашем TextView

  1. Вот почему мы говорим, что LayoutParams передаются родительскому элементу, как в упомянутой ссылке

ПРЕДУПРЕЖДЕНИЕ : Бесконечный источник путаницы!

Просмотр позиционирования внутри Layout s / ViewGroup s выполняется через LayoutParam s вызовы 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 - CENTERED, но текст находится в верхней части страницы.

TextView является CENTERED в RelativeLayout, но текст находится в верхней части окна "box"

Давайте используем android: гравитация для управления текстовой позицией INSIDE 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 /> 

Результат: Как и ожидалось, только внутренняя часть View изменилась

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

TLDR Теперь, если вы хотите игнорировать все выше и по-прежнему использовать android: gravity with RelativeLayout, RelativeLayout также представляет собой View поэтому у него есть свойство android: gravity, но вам нужно удалить другие свойства или LayoutParams, которые переопределяют поведение, определенное андроидом : Гравитационное свойство смотреть на андроид: гравитация при работе с 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> 

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