Процентная ширина в RelativeLayout
Я работаю над макетом формы для входа Activity
в моем приложении для Android. Изображение ниже, как я хочу, чтобы оно выглядело так:
Я смог добиться этого макета с помощью следующего XML. Проблема в том, что это немного хакерски. Мне пришлось жестко закодировать ширину для узла EditText. В частности, я должен был указать:
android:layout_width="172dp"
Я бы очень хотел дать процентную ширину для хоста и порта EditText's . (Что-то вроде 80% для хоста, 20% для порта.) Возможно ли это? Следующий XML работает на моем Droid, но, похоже, не работает на всех экранах. Я действительно хотел бы более надежное решение.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="@+id/host_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/home"
android:paddingLeft="15dp"
android:paddingTop="0dp"
android:text="host"
android:textColor="#a5d4e2"
android:textSize="25sp"
android:textStyle="normal" />
<TextView
android:id="@+id/port_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/home"
android:layout_toRightOf="@+id/host_input"
android:paddingTop="0dp"
android:text="port"
android:textColor="#a5d4e2"
android:textSize="25sp"
android:textStyle="normal" />
<EditText
android:id="@+id/host_input"
android:layout_width="172dp"
android:layout_height="wrap_content"
android:layout_below="@id/host_label"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="4dp"
android:background="@android:drawable/editbox_background"
android:inputType="textEmailAddress" />
<EditText
android:id="@+id/port_input"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_below="@id/host_label"
android:layout_marginTop="4dp"
android:layout_toRightOf="@id/host_input"
android:background="@android:drawable/editbox_background"
android:inputType="number" />
<TextView
android:id="@+id/username_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/host_input"
android:paddingLeft="15dp"
android:paddingTop="15dp"
android:text="username"
android:textColor="#a5d4e2"
android:textSize="25sp"
android:textStyle="normal" />
<EditText
android:id="@+id/username_input"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/username_label"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="4dp"
android:background="@android:drawable/editbox_background"
android:inputType="textEmailAddress" />
<TextView
android:id="@+id/password_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/username_input"
android:paddingLeft="15dp"
android:paddingTop="15dp"
android:text="password"
android:textColor="#a5d4e2"
android:textSize="25sp"
android:textStyle="normal" />
<EditText
android:id="@+id/password_input"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/password_label"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="4dp"
android:background="@android:drawable/editbox_background"
android:inputType="textPassword" />
<ImageView
android:id="@+id/home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_centerVertical="false"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="15dp"
android:scaleType="fitStart"
android:src="@drawable/home" />
<Button
android:id="@+id/login_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/password_input"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:text=" login "
android:textSize="18sp" >
</Button>
</RelativeLayout>
14 ответов
Вы ищете android:layout_weight
приписывать. Это позволит вам использовать проценты для определения вашего макета.
В следующем примере левая кнопка занимает 70% пространства, а правая кнопка 30%.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:text="left"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".70" />
<Button
android:text="right"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".30" />
</LinearLayout>
Он работает так же с любым видом, вы можете заменить кнопки некоторым EditText, чтобы соответствовать вашим потребностям.
Обязательно установите layout_width
в 0dp
или ваши взгляды могут быть неправильно масштабированы.
Обратите внимание, что весовая сумма не должна равняться 1, мне просто легче читать вот так. Вы можете установить первый вес на 7, а второй на 3, и это даст тот же результат.
Это не совсем отвечает первоначальному вопросу, который был для разделения 70/30, но в особом случае разделения 50/50 между компонентами есть способ: поместите невидимую стойку в центр и используйте ее, чтобы расположить две составляющие интереса.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View android:id="@+id/strut"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_centerHorizontal="true"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignRight="@id/strut"
android:layout_alignParentLeft="true"
android:text="Left"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/strut"
android:layout_alignParentRight="true"
android:text="Right"/>
</RelativeLayout>
Поскольку это довольно распространенный случай, это решение - больше, чем просто любопытство. Это немного взломано, но эффективно, потому что пустая стойка нулевого размера должна стоить очень мало.
В целом, однако, лучше не ожидать слишком многого от стандартных макетов Android...
Обновление 1
Как указано @EmJiHash, PercentRelativeLayout устарела на уровне API 26.0.0
Ниже цитируем гугл комментарий:
Этот класс устарел на уровне API 26.0.0. рассмотрите использование ConstraintLayout и связанных макетов вместо этого. Ниже показано, как реплицировать функциональность процентных макетов с помощью ConstraintLayout.
Google представил новый API под названием android.support.percent
Тогда вы можете просто указать процент, чтобы взять на просмотр
Добавить зависимость компиляции как
compile 'com.android.support:percent:22.2.0
в этом, PercentRelativeLayout - это то, что мы можем сделать в процентах
<android.support.percent.PercentRelativeLayout
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">
<ImageView
app:layout_widthPercent="50%"
app:layout_heightPercent="50%"
app:layout_marginTopPercent="25%"
app:layout_marginLeftPercent="25%"/>
</android.support.percent.PercentRelativeLayout>
Вы не можете использовать проценты для определения размеров представления внутри RelativeLayout. Лучший способ сделать это - использовать LinearLayout и веса или пользовательский макет.
Вы можете взглянуть на новую библиотеку поддержки процентов.
compile 'com.android.support:percent:22.2.0'
Так как PercentRelativeLayout был объявлен устаревшим в 26.0.0, а вложенные макеты, такие как LinearLayout внутри RelativeLayout, оказывают негативное влияние на производительность ( Понимание преимуществ производительности ConstraintLayout), лучшим вариантом для достижения процентной ширины является замена RelativeLayout на ConstraintLayout.
Это можно решить двумя способами.
РЕШЕНИЕ № 1 Использование указателей с процентным смещением
<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">
<TextView
android:id="@+id/host_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Host"
android:layout_marginTop="16dp"
android:layout_marginLeft="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="@+id/host_input" />
<TextView
android:id="@+id/port_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Port"
android:layout_marginTop="16dp"
android:layout_marginLeft="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="@+id/port_input" />
<EditText
android:id="@+id/host_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:inputType="textEmailAddress"
app:layout_constraintTop_toBottomOf="@+id/host_label"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/guideline" />
<EditText
android:id="@+id/port_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:inputType="number"
app:layout_constraintTop_toBottomOf="@+id/port_label"
app:layout_constraintLeft_toLeftOf="@+id/guideline"
app:layout_constraintRight_toRightOf="parent" />
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.8" />
</android.support.constraint.ConstraintLayout>
РЕШЕНИЕ № 2 Использование цепочки с взвешенной шириной для EditText
<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">
<TextView
android:id="@+id/host_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Host"
android:layout_marginTop="16dp"
android:layout_marginLeft="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="@+id/host_input" />
<TextView
android:id="@+id/port_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Port"
android:layout_marginTop="16dp"
android:layout_marginLeft="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="@+id/port_input" />
<EditText
android:id="@+id/host_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:inputType="textEmailAddress"
app:layout_constraintHorizontal_weight="0.8"
app:layout_constraintTop_toBottomOf="@+id/host_label"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/port_input" />
<EditText
android:id="@+id/port_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:inputType="number"
app:layout_constraintHorizontal_weight="0.2"
app:layout_constraintTop_toBottomOf="@+id/port_label"
app:layout_constraintLeft_toRightOf="@+id/host_input"
app:layout_constraintRight_toRightOf="parent" />
</android.support.constraint.ConstraintLayout>
В обоих случаях вы получите что-то вроде этого
Вы можете использовать PercentRelativeLayout. Это недавнее недокументированное дополнение к Библиотеке поддержки проектирования, позволяющее указывать не только элементы относительно друг друга, но и общий процент доступного пространства.
Подкласс RelativeLayout, который поддерживает измерения и поля в процентах. Вы можете указать измерение или поле дочернего элемента, используя атрибуты с суффиксом "Процент".
<android.support.percent.PercentRelativeLayout
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">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_widthPercent="50%"
app:layout_heightPercent="50%"
app:layout_marginTopPercent="25%"
app:layout_marginLeftPercent="25%"/>
</android.support.percent.PercentFrameLayout>
Пакет Percent предоставляет API для поддержки добавления и управления процентными измерениями в вашем приложении.
Чтобы использовать, вам нужно добавить эту библиотеку в ваш список зависимостей Gradle:
dependencies {
compile 'com.android.support:percent:22.2.0'//23.1.1
}
Я решил это, создав собственный вид:
public class FractionalSizeView extends View {
public FractionalSizeView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FractionalSizeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(width * 70 / 100, 0);
}
}
Это невидимая распорка, которую я могу использовать для выравнивания других представлений в RelativeLayout.
Обновить
Как указано @EmJiHash, PercentRelativeLayout и PercentFrameLayout устарели на уровне API 26.0.0
Рассмотрите возможность использования ConstraintLayout
Google представил новый API под названием android.support.percent
1) PercentRelativeLayout
2) PercentFrameLayout
Добавить зависимость компиляции как
compile 'com.android.support:percent:23.1.1'
Вы можете указать размерность в процентах, чтобы получить как преимущество RelativeLayout
и процент
<android.support.percent.PercentRelativeLayout
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"/>
<TextView
app:layout_widthPercent="40%"
app:layout_heightPercent="40%"
app:layout_marginTopPercent="15%"
app:layout_marginLeftPercent="15%"/>
</android.support.percent.PercentRelativeLayout/>
PercentRelativeLayout не рекомендуется использовать в Revision 26.0.0 библиотеки поддержки.
Google представил новый макет под названием ConstraintLayout.
Добавьте библиотеку в качестве зависимости в файл build.gradle уровня модуля:
dependencies {
compile 'com.android.support.constraint:constraint-layout:1.0.1'
}
просто добавьте в файл макета:
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.constraint.ConstraintLayout>
Ограничения
Ограничения помогут вам выровнять виджеты. Вы можете использовать привязки, такие как дескрипторы ограничений, показанные ниже, для определения правил выравнивания между различными виджетами.
Wrap Content
: Представление расширяется по мере необходимости, чтобы соответствовать его содержимому.Match Constraints
: Представление расширяется по мере необходимости, чтобы соответствовать определению его ограничений после учета полей. Однако, если данное измерение имеет только одно ограничение, то представление расширяется, чтобы соответствовать его содержимому. Использование этого режима на высоте или ширине также позволяет вам установить соотношение размеров.Fixed
: Вы указываете определенное измерение в текстовом поле ниже или изменяете размер представления в редакторе.Spread
: Представления распределяются равномерно (после учета полей). Это по умолчанию.Spread inside
: Первый и последний вид прикреплены к ограничениям на каждом конце цепочки, а остальные распределены равномерно.Weighted
: Когда для цепочки установлено либо распространение, либо распространение внутри, вы можете заполнить оставшееся пространство, установив одно или несколько представлений в "соответствие ограничениям" (0dp). По умолчанию пространство равномерно распределяется между каждым представлением, для которого установлено "соответствие ограничениям", но вы можете назначить вес важности для каждого представления, используя атрибуты layout_constraintHor horizontal_weight и layout_constraintVertical_weight. Если вы знакомы с layout_weight в линейном макете, это работает точно так же. Таким образом, представление с наибольшим значением веса получает наибольшее количество места; виды с одинаковым весом получают одинаковое количество места.Packed
: Представления упакованы вместе (после учета полей). Затем вы можете отрегулировать смещение всей цепи (влево / вправо или вверх / вниз), изменив смещение вида головы.Center Horizontally or Center Vertically
: Чтобы быстро создать цепочку видов, выделите их все, щелкните правой кнопкой мыши один из видов и выберите "Центр по горизонтали" или "Центр по вертикали", чтобы создать горизонтальную или вертикальную цепочку.Baseline alignment
: Выровняйте текстовую базовую линию представления к текстовой базовой линии другого представления.Constrain to a guideline
: Вы можете добавить вертикальную или горизонтальную направляющую, к которой можно ограничить виды, и эта направляющая будет невидимой для пользователей приложения. Вы можете расположить направляющую в макете, основываясь на единицах dp или процентах относительно края макета.Adjust the constraint bias
: Когда вы добавляете ограничение к обеим сторонам представления (и размер представления для того же измерения является либо "фиксированным", либо "переносом содержимого"), представление становится центрированным между двумя ограничениями с смещением по умолчанию 50%. Вы можете настроить смещение, перетаскивая ползунок смещения в окне "Свойства".Set size as a ratio
: Вы можете установить размер вида в таком соотношении, как 16:9, если хотя бы одно из размеров вида установлено в "соответствие ограничениям" (0dp).
Вы можете узнать больше из официального документа.
Интересно, что, основываясь на ответе @olefevre, можно делать не только макеты 50/50 с "невидимыми распорками", но и всевозможные макеты, включающие степень двойки.
Например, вот макет, который разрезает ширину на четыре равные части (фактически три, с весами 1, 1, 2):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<View
android:id="@+id/strut"
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:background="#000000" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/strut" >
<View
android:id="@+id/left_strut"
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_toLeftOf="@+id/strut"
android:layout_centerHorizontal="true"
android:background="#000000" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignRight="@+id/left_strut"
android:text="Far Left" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_toRightOf="@+id/left_strut"
android:text="Near Left" />
</RelativeLayout>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/strut"
android:layout_alignParentRight="true"
android:text="Right" />
</RelativeLayout>
Вы можете сделать это с помощью весов макета. Вес определяет, как разделить невостребованные части экрана. Дайте каждому EditText layout_width 0 и некоторый пропорциональный вес. То есть, дайте одному вес 2, а другому вес 1, если вы хотите, чтобы первый занимал вдвое больше места.
Просто поместите два хоста и порт textviews в независимую горизонтальную линейную область и используйте android:layout_weight, чтобы получить процент
Проверьте https://github.com/mmin18/FlexLayout который вы можете использовать в процентах или Java-выражении непосредственно в макете XML.
<EditText
app:layout_left="0%"
app:layout_right="60%"
app:layout_height="wrap_content"/>
<EditText
app:layout_left="prev.right+10dp"
app:layout_right="100%"
app:layout_height="wrap_content"/>