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

Я уже понимаю, что если я использую 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 (видимо) нет?

  1. если ваша цель - поместить TextView в горизонтальный центр макета / экрана, вы должны позволить RelativeLayout знать!

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

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

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

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

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

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

ВНИМАНИЕ: Бесконечный источник путаницы!

Посмотреть расположение внутри Layoutс / ViewGroupS делается через 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 находится в центре, но текст на вершине

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>

Другие вопросы по тегам