Контейнер RelativeLayout задает относительное позиционирование вложенных элементов относительно сторон контейнера или относительно других элементов.
Позиционирование и размеры элементов внутри RelativeLayout определяются с помощью ограничений, которые в XAML представляют следующие прикрепляемые свойства:
RelativeLayout.XConstraint
: задает расположение относительно оси X
RelativeLayout.YConstraint
: задает расположение относительно оси Y
RelativeLayout.HeightConstraint
: задает высоту элемента
RelativeLayout.WidthConstraint
: задает ширину элемента
RelativeLayout.HeightConstraint
и RelativeLayout.WidthConstraint
устанавливаются с помощью числоого значения. А
RelativeLayout.XConstraint
и RelativeLayout.YConstraint
задаются с помощью расширения разметки ConstraintExpression, которое включает следующую информацию:
Type: тип ограничения, который указывает, применяется ограничение относительно контейнера или других элементов
Property: свойство, на основании которого устанавливается ограничение
Factor: множитель, на который умножается длина между границами контейнера (0 и 1 - крайние значения)
Constant: смещение относительно контейнера или относительно элемента (в зависимости от значения свойства Type)
ElementName: название элемента, к которому применяется ограничение
Например, позиционирование элемента BoxView в RelativeLayout в XAML:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="HelloApp.MainPage"> <RelativeLayout> <BoxView WidthRequest="100" HeightRequest="100" Color="Blue" RelativeLayout.XConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.5, Constant=-50}" /> </RelativeLayout> </ContentPage>
В данном случае у BoxView устанавливается ограничение RelativeLayout.XConstraint
, которое задает смещение относительно оси X,
то есть остступ слева. По умолчанию он равен. В данном случае Type=RelativeToParent
указывает, что смещение будет идти относительно контейнера.
Property=Width
говорит, что при вычислении значения используется ширина (контейнера).
Выражение Factor=0.5
указывает, что для вычисления
значения надо умножить предельное значение свойства из Property на 0.5, то есть ширина контейнера умножается на 0.5.
Выражение Constant=-50
добавляет дополнительное смещение в виде 50 назад. Это смещение может как положительным, так и отрицательным.
То есть в итоге мы получаем x = Width * 0.5 - 50. Фактически в данном случае BoxView центрируется по ширине.
Подобным образом добавим второе ограничение RelativeLayout.YConstraint
:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="HelloApp.MainPage"> <RelativeLayout> <BoxView WidthRequest="100" HeightRequest="100" Color="Blue" RelativeLayout.XConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.5, Constant=-50}" RelativeLayout.YConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.5, Constant=-50}" /> </RelativeLayout> </ContentPage>
При установке размеров элементов в RelativeLayout в XAML мы можем использовать две стратегии:
Установить значения через свойства HeightRequest
и WidthRequest
у элементов
Установить ограничения RelativeLayout.HeightConstraint
и RelativeLayout.WidthConstraint
Первая сратегия продемонстрирована на примерах выше, где у BoxView устанавливались атрибуты HeightRequest
и WidthRequest
.
Теперь применим другую стратегию:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="HelloApp.MainPage"> <RelativeLayout> <BoxView Color="Blue" RelativeLayout.XConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.5, Constant=-50}" RelativeLayout.YConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.5, Constant=-50}" RelativeLayout.WidthConstraint="100" RelativeLayout.HeightConstraint="100" /> </RelativeLayout> </ContentPage>
Перепишим предыдущий пример в C#:
class MainPage : ContentPage { public MainPage() { RelativeLayout relativeLayout = new RelativeLayout(); BoxView blueBox = new BoxView { BackgroundColor = Color.Blue }; relativeLayout.Children.Add(blueBox, Constraint.RelativeToParent((parent) => { return parent.Width * 0.5 - 50; // установка координаты X }), Constraint.RelativeToParent((parent) => { return parent.Height * 0.5 - 50; // установка координаты Y }), Constraint.Constant(100), // установка ширины Constraint.Constant(100) // установка высоты ); Content = relativeLayout; } }
Метод Children.Add()
у RelativeLayout имеет ряд перегрузок, позволяющих определить относительные координаты элемента. В качестве первого параметра передается
сам элемент. Остальные параметры не являются обязательными, и их набор можно варьировать. Он последовательно принимает значения для
x-координаты верхнего левого угла элемента, y-координаты, ширины и высоты.
Второй и третий параметры метода устанавливают координаты X и Y. Здесь нам надо передать объект Constraint, который будет возвращать какое-нибудь значение.
Это значение может быть константным и задаваться с помощью метода Constraint.Constant
. Либо это может быть значение, вычисляемое динамически, например,
относительно параметров контейнера.
Для позиционирования относительно контейнера значения устанавливаются с помощью метода Constraint.RelativeToParent()
, который в качестве параметра использует делегат. В лямбда-выражение,
которое применяется за место делегата, передается значение parent
, содержащее ссылку на родительский контейнер, то есть на RalativeLayout. Через свойства
parent.Width
и parent.Height
можо получить ширину и высоту контейнера в процессе выполнения, а оператор
return возвращает непосредственное значение.
Для определения размеров элементов в RelativeLayout в коде C# мы можем использовать одну из трех опций:
Установить значения через свойства HeightRequest
и WidthRequest
у элементов
Установить константное значение через метод Constraint.Constant()
Установить динамическое значение через метод Constraint.RelativeToParent
, который также как и в случае с координатами может принимать во внимание параметры контейнера
При позиционировании относительно другого элемента необходимо задать параметр ElementName
:
Позиционирование относительно элемента в XAML:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="HelloApp.MainPage"> <RelativeLayout> <Label x:Name="lbl" Text="RelativeLayout" RelativeLayout.XConstraint = "{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.5, Constant=-50}" RelativeLayout.YConstraint = "{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.5, Constant=-150}" /> <BoxView Color="Blue" RelativeLayout.XConstraint = "{ConstraintExpression Type=RelativeToView, ElementName=lbl, Property=X, Factor=1, Constant=-30}" RelativeLayout.YConstraint = "{ConstraintExpression Type=RelativeToView, ElementName=lbl, Property=Y, Factor=1, Constant=30}" RelativeLayout.WidthConstraint = "150" RelativeLayout.HeightConstraint = "100"/> </RelativeLayout> </ContentPage>
В данном случае позиционирование элемента Label устанавливается относительно контейнера RelativeLayout. А элемент BoxView устанавливается относительно элемента Label. В данном случае BoxView.X = lbl.X * 1 - 30. Аналогично вычисляется положение по оси Y.
Для позиционирования элемента в коде C# относительно других элементов мы могли бы использовать метод Constraint.RelativeToView()
вместо
Constraint.RelativeToParent()
. Например, перепишем предыдущий пример в C#:
using Xamarin.Forms; namespace HelloApp { public partial class MainPage : ContentPage { public MainPage() { //InitializeComponent(); RelativeLayout relativeLayout = new RelativeLayout(); Label label = new Label { Text = "RelativeLayout"}; BoxView blueBox = new BoxView { BackgroundColor = Color.Blue }; relativeLayout.Children.Add(label, Constraint.RelativeToParent((parent) => { return parent.Width * 0.5 - 50; // установка координаты X }), Constraint.RelativeToParent((parent) => { return parent.Height * 0.5 - 150; // установка координаты Y }) ); relativeLayout.Children.Add(blueBox, Constraint.RelativeToView(label, (parent, view) => { return label.X - 30; // установка координаты X }), Constraint.RelativeToView(label, (parent, view) => { return label.Y + 30; // установка координаты Y }), Constraint.Constant(150), // установка ширины Constraint.Constant(100) // установка высоты ); Content = relativeLayout; } } }
В метод Constraint.RelativeToView()
передается элемент, относительно которого задается позиционирование (то есть label), и далее передается
делегат, входные параметры которого - контейнер и элемент.