Гибкие макеты на основе XAML
Система макетов XAML позволяет применять функцию автоматического выбора размера, панели макетов, визуальные состояния для создания адаптивного интерфейса. Благодаря гибкому макету ваше приложение будет прекрасно смотреться на экранах с различными размерами окна, разными разрешениями, плотностью пикселей и ориентацией. XAML также можно использовать для изменения положения, изменения размера, показа и скрытия или изменения архитектуры пользовательского интерфейса приложения, как описано в статье Методы создания адаптивного дизайна. В этой статье описано, как реализовывать гибкие макеты с помощью XAML.
Гибкие макеты со свойствами и панелями
Основа гибкого макета — это правильное применение свойств и панелей макета XAML для гибкого изменения положения, изменения размеров и адаптации содержимого.
Система макета XAML поддерживает как статические, так и гибкие макеты. В статическом макете вы предоставляете элементы управления явными размерами пикселей и позициями. Когда пользователь изменяет разрешение или ориентацию устройства, пользовательский интерфейс не изменяется. Статические макеты могут быть обрезаны в разных форм-факторах и размерах отображения. Гибкие макеты, напротив, сжимаются, растягиваются и видоизменяются, адаптируясь к доступному на устройстве визуальному пространству экрана.
На практике для создания пользовательского интерфейса используется сочетание статических и гибких элементов. Можно использовать статические элементы и значения в некоторых местах, но пользовательский интерфейс в целом должен адаптироваться к разным разрешениям, размерам экрана и представлениям.
В этой статье описано, как создать гибкий макет с помощью свойств и панелей макета XAML.
Свойства макета
Свойства макета позволяют управлять размером и положением элемента. Для создания гибкого макета используйте автоматический или пропорциональный размер элементов, чтобы дочерние элементы панелей макета могли разместиться необходимым способом.
Ниже приведены некоторые распространенные свойства макета и способы их использования для создания гибких макетов.
Height и Width
Свойства Height и Width позволяют определить размер элемента. Можно использовать фиксированные значения, измеряемые в эффективных пикселях, или использовать автоматический или пропорциональный размер.
Функция автоматического выбора размера позволяет изменяет размер элементов пользовательского интерфейса в соответствии с их содержимым или размером родительского контейнера. Вы также можете использовать автоматическое изменение размера со строками и столбцами сетки. Чтобы использовать автоматическое изменение размера, задайте для элементов пользовательского интерфейса значение "Высота" и (или) ширину элементов пользовательского интерфейса автоматически.
Примечание.
Будет ли элемент изменять размер согласно своему содержимому или контейнеру, зависит от того, как родительский контейнер обработает изменение размеров его дочерних элементов. Дополнительные сведения см. в разделе Панели макета далее в этой статье.
Пропорциональное изменение размеров, которое задается символом звездочки, распределяет доступное пространство среди строк и столбцов сетки с помощью взвешенных пропорций. В XAML значения звезд выражаются как * (или n* для взвешированного размера звезд). Например, чтобы указать, что один столбец превышает 5 раз шире второго столбца в макете 2 столбца, используйте "5*" и "*" для свойств Width в элементах ColumnDefinition.
Этот пример объединяет фиксированный, автоматический и пропорциональный размер в сетке с 4 столбцами.
Column | Определение параметров | Description |
---|---|---|
Column_1 | Автоматически | Размер столбца будет соответствовать его содержимому. |
Column_2 | * | После вычисления автоматических столбцов столбец получает часть оставшейся ширины. Column_2 будет в два раза больше, чем Column_4. |
Column_3 | 44 | Столбец будет иметь ширину в 44 пикселях. |
Column_4 | 2* | После вычисления автоматических столбцов столбец получает часть оставшейся ширины. Column_4 будет в два раза больше, чем Column_2. |
Ширина столбца по умолчанию — "*", поэтому не нужно явно задавать это значение для второго столбца.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="44"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Column 1 sizes to its content." FontSize="24"/>
</Grid>
В конструкторе XAML Visual Studio результат выглядит следующим образом.
Чтобы получить размер элемента во время выполнения, используйте свойства ActualHeight и ActualWidth только для чтения вместо Height и Width.
Ограничения размера
При использовании автоматического изменения размера в пользовательском интерфейсе может потребоваться поместить ограничения на размер элемента. Свойства MinWidth MaxWidth/ и MinHeight MaxHeight/ можно задать для указания значений, ограничивающих размер элемента, позволяя изменять размер жидкости.
В сетке minWidth/MaxWidth также можно использовать с определениями столбцов, а MinHeight/MaxHeight можно использовать с определениями строк.
Выравнивание
Используйте свойства HorizontalAlignment и VerticalAlignment, чтобы указать, как элемент должен размещаться в родительском контейнере.
- Значения для HorizontalAlignment: Left, Center, Right и Stretch.
- Значения для VerticalAlignment: Top, Center, Bottom и Stretch.
При выравнивании Stretch элементы заполняют все пространство, которое они предоставляются в родительском контейнере. Stretch — это значение по умолчанию для обоих свойств выравнивания. Однако некоторые элементы управления, такие как Button, переопределяют это значение в их стиле по умолчанию. Любой элемент, который может содержать дочерние элементы, может обрабатывать значение Stretch для свойств HorizontalAlignment и VerticalAlignment уникальным образом. Например, элемент с использованием значений Stretch по умолчанию, помещенных в сетку, заполняет ячейку, содержащую ее. Тот же элемент, который помещается в размер холста в его содержимое. Дополнительные сведения о том, как каждая панель обрабатывает значение Stretch, см. в статье о панелях макета .
Дополнительные сведения см. в статье "Выравнивание", "Поля" и "Заполнение" и "Горизонтальнаяalignment" и "Вертикальный".
Видимость
Можно отобразить или скрыть элемент, задав его свойство Видимости одному из значений перечисления Видимости: Видимый или Свернутый. Если элемент свернут, он не занимает места в макете пользовательского интерфейса.
Вы можете изменить свойство Видимости элемента в коде или визуальном состоянии. При изменении видимости элемента все дочерние элементы также изменяются. Вы можете заменить разделы пользовательского интерфейса, открыв одну панель при сворачивании другой.
Совет
Если в пользовательском интерфейсе есть элементы, которые свернуты (Collapsed) по умолчанию, объекты продолжают создаваться при запуске, даже если они невидимы. Вы можете отложить загрузку этих элементов до тех пор, пока они не будут показаны с помощью атрибута x:Load, чтобы отложить создание объектов. Это может повысить производительность запуска. Дополнительные сведения см. в атрибуте x:Load.
Ресурсы стиля
Вам не нужно задавать каждое значение свойства по отдельности в элементе управления. Обычно более эффективно группировать значения свойств в ресурс Style и применять стиль к элементу управления. Это особенно верно, если необходимо применить одни и те же значения свойств ко многим элементам управления. Дополнительные сведения об использовании стилей см. в разделе "Стилизация элементов управления".
Панели макета
Чтобы разместить визуальные объекты, их необходимо поместить в панель или другой объект контейнера. Платформа XAML предоставляет различные классы панелей, такие как Canvas, Grid, RelativePanel и StackPanel, которые служат контейнерами и позволяют размещать и упорядочивать элементы пользовательского интерфейса в них.
Главное, чтобы при выборе панели макета было то, как панель позиций и размеров ее дочерних элементов. Кроме того, может потребоваться рассмотреть, как перекрывающиеся дочерние элементы сложены поверх друг друга.
Ниже приведено сравнение основных функций элементов управления панели, предоставляемых в платформе XAML.
Элемент управления Panel | Description |
---|---|
Canvas | Холст не поддерживает гибкий пользовательский интерфейс; вы управляете всеми аспектами размещения и изменения размера дочерних элементов. Обычно он используется для специальных случаев, таких как создание графики или определение небольших статических областей более крупного адаптивного пользовательского интерфейса. Код или визуальные состояния можно использовать для изменения положения элементов во время выполнения. |
Сетка | Grid поддерживает изменение размера дочерних элементов. Код или визуальные состояния можно использовать для изменения положения и перетека элементов. |
RelativePanel | |
StackPanel | |
VariableSizedWrapGrid |
Подробные сведения и примеры этих панелей см . на панелях макета.
Панели макета позволяют упорядочивать пользовательский интерфейс в логические группы элементов управления. При использовании их с соответствующими параметрами свойств вы получите некоторую поддержку автоматического изменения размера, изменения положения и перетекания элементов пользовательского интерфейса. Однако большинству макетов пользовательского интерфейса требуется дальнейшее изменение, если существуют значительные изменения размера окна. Для этого можно использовать визуальные состояния.
Адаптивные макеты с визуальными состояниями и триггерами состояния
Используйте визуальные состояния, чтобы внести значительные изменения в пользовательский интерфейс на основе размера окна или других изменений.
Когда окно приложения увеличивается или сжимается за пределами определенного объема, может потребоваться изменить свойства макета для изменения положения, изменения размера, изменения потока, отображения или замены разделов пользовательского интерфейса. Вы можете определить различные визуальные состояния пользовательского интерфейса и применить их, когда ширина окна или высота окна пересекает указанное пороговое значение.
VisualState определяет значения свойств, применяемые к элементу, когда оно находится в определенном состоянии. Вы группируете визуальные состояния в VisualStateManager , которое применяет соответствующий VisualState при выполнении указанных условий. AdaptiveTrigger предоставляет простой способ установки порогового значения (или "точки останова"), при котором применяется состояние в XAML. Или вызовите метод VisualStateManager.GoToState в коде, чтобы применить визуальное состояние. Примеры обоих способов показаны в следующих разделах.
Настройка визуальных состояний в коде
Чтобы применить визуальное состояние из кода, вызовите метод VisualStateManager.GoToState . Например, чтобы применить состояние, когда окно приложения имеет определенный размер, обработайте событие SizeChanged и вызовите GoToState , чтобы применить соответствующее состояние.
Здесь VisualStateGroup содержит два определения VisualState. Во-первых, DefaultState
пусто. При применении применяются значения, определенные на странице XAML. Во-вторых, WideState
изменяет свойство DisplayMode в SplitView на Inline и открывает область. Это состояние применяется в обработчике событий SizeChanged, если ширина окна превышает 640 эффективных пикселей.
Примечание.
Windows не предоставляет средств, благодаря которым приложение могло бы определить устройство, на котором оно запущено. Он может сказать, что семейство устройств (рабочий стол и т. д.) приложение запущено, эффективное разрешение и объем свободного пространства экрана для приложения (размер окна приложения). Мы рекомендуем задавать визуальные состояния для размеров экрана и точек прерывания.
<Page ...
SizeChanged="CurrentWindow_SizeChanged">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="DefaultState">
<Storyboard>
</Storyboard>
</VisualState>
<VisualState x:Name="WideState">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="SplitView.DisplayMode"
Storyboard.TargetName="mySplitView">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<SplitViewDisplayMode>Inline</SplitViewDisplayMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="SplitView.IsPaneOpen"
Storyboard.TargetName="mySplitView">
<DiscreteObjectKeyFrame KeyTime="0" Value="True"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<SplitView x:Name="mySplitView" DisplayMode="CompactInline"
IsPaneOpen="False" CompactPaneLength="20">
<!-- SplitView content -->
<SplitView.Pane>
<!-- Pane content -->
</SplitView.Pane>
</SplitView>
</Grid>
</Page>
private void CurrentWindow_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
if (e.Size.Width > 640)
VisualStateManager.GoToState(this, "WideState", false);
else
VisualStateManager.GoToState(this, "DefaultState", false);
}
// YourPage.h
void CurrentWindow_SizeChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::SizeChangedEventArgs const& e);
// YourPage.cpp
void YourPage::CurrentWindow_SizeChanged(IInspectable const& sender, SizeChangedEventArgs const& e)
{
if (e.NewSize.Width > 640)
VisualStateManager::GoToState(*this, "WideState", false);
else
VisualStateManager::GoToState(*this, "DefaultState", false);
}
Настройка визуальных состояний в разметке XAML
До Windows 10 определения VisualState требуются объекты Раскадровки для изменений свойств, и вам пришлось вызвать GoToState в коде для применения состояния. Это показано в предыдущем примере. Вы по-прежнему увидите множество примеров, использующих этот синтаксис, или у вас может быть существующий код, использующий его.
Начиная с Windows 10, можно использовать упрощенный синтаксис setter, показанный здесь, и вы можете использовать StateTrigger в разметке XAML для применения состояния. Триггеры состояния используются для создания простых правил, которые автоматически активируют изменения визуального состояния в ответ на событие приложения.
Этот пример выполняет то же самое, что и предыдущий пример, но использует упрощенный синтаксис Setter вместо раскадровки для определения изменений свойств. Вместо вызова GoToState используется встроенный триггер состояния AdaptiveTrigger для применения состояния. При использовании триггеров состояния не требуется определять пустое DefaultState
. Параметры по умолчанию автоматически применяются, когда условия триггера состояния больше не выполняются.
<Page ...>
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<!-- VisualState to be triggered when the
window width is >=640 effective pixels. -->
<AdaptiveTrigger MinWindowWidth="640" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="mySplitView.DisplayMode" Value="Inline"/>
<Setter Target="mySplitView.IsPaneOpen" Value="True"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<SplitView x:Name="mySplitView" DisplayMode="CompactInline"
IsPaneOpen="False" CompactPaneLength="20">
<!-- SplitView content -->
<SplitView.Pane>
<!-- Pane content -->
</SplitView.Pane>
</SplitView>
</Grid>
</Page>
Внимание
В предыдущем примере для элемента Grid настраивается прикрепленное свойство VisualStateManager.VisualStateGroups. При использовании StateTriggers всегда убедитесь, что VisualStateGroups присоединяется к первому дочернему элементу корневого элемента, чтобы триггеры вступают в силу автоматически. (Здесь, Сетка является первым дочерним элементом корневой страницы .)
Синтаксис присоединенного свойства
В VisualState обычно задается значение для свойства элемента управления или для одного из присоединенных свойств панели, содержащей элемент управления. При установке присоединенного свойства используйте круглые скобки вокруг имени присоединенного свойства.
В этом примере показано, как задать присоединенное свойство RelativePanel.AlignHorizontalCenterWithPanel в textBox с именемmyTextBox
. Первый XAML использует синтаксис ObjectAnimationUsingKeyFrames, а второй использует синтаксис Setter.
<!-- Set an attached property using ObjectAnimationUsingKeyFrames. -->
<ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="(RelativePanel.AlignHorizontalCenterWithPanel)"
Storyboard.TargetName="myTextBox">
<DiscreteObjectKeyFrame KeyTime="0" Value="True"/>
</ObjectAnimationUsingKeyFrames>
<!-- Set an attached property using Setter. -->
<Setter Target="myTextBox.(RelativePanel.AlignHorizontalCenterWithPanel)" Value="True"/>
Триггеры пользовательского состояния
Класс StateTrigger можно расширить для создания пользовательских триггеров для широкого спектра сценариев. Например, можно создать StateTrigger для активации различных состояний на основе типа входных данных, а затем увеличить поля вокруг элемента управления при касании типа ввода. Или создайте StateTrigger для применения различных состояний в зависимости от семейства устройств, на которые выполняется приложение. Примеры создания пользовательских триггеров и их использования для создания оптимизированных интерфейсов пользовательского интерфейса в одном представлении XAML см . в примере триггеров состояния.
Визуальные состояния и стили
Ресурсы стиля можно использовать в визуальных состояниях для применения набора изменений свойств к нескольким элементам управления. Дополнительные сведения об использовании стилей см. в разделе "Стилизация элементов управления".
В этом упрощенном коде XAML из примера триггеров состояния ресурс стиля применяется к кнопке для настройки размера и полей для ввода мыши или сенсорного ввода. Полный код и определение пользовательского триггера состояния см. в примере триггеров состояния.
<Page ... >
<Page.Resources>
<!-- Styles to be used for mouse vs. touch/pen hit targets -->
<Style x:Key="MouseStyle" TargetType="Rectangle">
<Setter Property="Margin" Value="5" />
<Setter Property="Height" Value="20" />
<Setter Property="Width" Value="20" />
</Style>
<Style x:Key="TouchPenStyle" TargetType="Rectangle">
<Setter Property="Margin" Value="15" />
<Setter Property="Height" Value="40" />
<Setter Property="Width" Value="40" />
</Style>
</Page.Resources>
<RelativePanel>
<!-- ... -->
<Button Content="Color Palette Button" x:Name="MenuButton">
<Button.Flyout>
<Flyout Placement="Bottom">
<RelativePanel>
<Rectangle Name="BlueRect" Fill="Blue"/>
<Rectangle Name="GreenRect" Fill="Green" RelativePanel.RightOf="BlueRect" />
<!-- ... -->
</RelativePanel>
</Flyout>
</Button.Flyout>
</Button>
<!-- ... -->
</RelativePanel>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="InputTypeStates">
<!-- Second set of VisualStates for building responsive UI optimized for input type.
Take a look at InputTypeTrigger.cs class in CustomTriggers folder to see how this is implemented. -->
<VisualState>
<VisualState.StateTriggers>
<!-- This trigger indicates that this VisualState is to be applied when MenuButton is invoked using a mouse. -->
<triggers:InputTypeTrigger TargetElement="{x:Bind MenuButton}" PointerType="Mouse" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="BlueRect.Style" Value="{StaticResource MouseStyle}" />
<Setter Target="GreenRect.Style" Value="{StaticResource MouseStyle}" />
<!-- ... -->
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<!-- Multiple trigger statements can be declared in the following way to imply OR usage.
For example, the following statements indicate that this VisualState is to be applied when MenuButton is invoked using Touch OR Pen.-->
<triggers:InputTypeTrigger TargetElement="{x:Bind MenuButton}" PointerType="Touch" />
<triggers:InputTypeTrigger TargetElement="{x:Bind MenuButton}" PointerType="Pen" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="BlueRect.Style" Value="{StaticResource TouchPenStyle}" />
<Setter Target="GreenRect.Style" Value="{StaticResource TouchPenStyle}" />
<!-- ... -->
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Page>
См. также
Windows developer