Гибкие макеты на основе XAML
Система макетов XAML позволяет применять функцию автоматического выбора размера, панели макетов, визуальные состояния для создания адаптивного интерфейса. Благодаря гибкому макету ваше приложение будет прекрасно смотреться на экранах с различными размерами окна, разными разрешениями, плотностью пикселей и ориентацией. XAML также можно использовать для изменения положения, изменения размера, показа и скрытия или изменения архитектуры пользовательского интерфейса приложения, как описано в статье Методы создания адаптивного дизайна. В этой статье описано, как реализовывать гибкие макеты с помощью XAML.
Гибкие макеты со свойствами и панелями
Основа гибкого макета — это правильное применение свойств и панелей макета XAML для гибкого изменения положения, изменения размеров и адаптации содержимого.
Система макетов XAML поддерживает как статические, так и гибкие макеты. В статическом макете элементам управления прямо назначаются размеры пикселей и положения. Если пользователь меняет разрешение или ориентацию устройства, пользовательский интерфейс не меняется. Статические макеты могут оказаться обрезанными при различных конструктивных параметрах и размерах изображения. Гибкие макеты, напротив, сжимаются, растягиваются и видоизменяются, адаптируясь к доступному на устройстве визуальному пространству экрана.
На практике используется сочетание статических и гибких элементов для создания пользовательского интерфейса. Можно использовать статические элементы и значения в некоторых местах, но пользовательский интерфейс в целом должен адаптироваться к разным разрешениям, размерам экрана и представлениям.
В этой статье описано, как создать гибкий макет с помощью свойств и панелей макета XAML.
Свойства макета
Свойства макета позволяют управлять размером и положением элемента. Для создания гибкого макета используйте автоматический или пропорциональный размер элементов, чтобы дочерние элементы панелей макета могли разместиться необходимым способом.
Ниже приведены некоторые распространенные свойства макета и способы их использования для создания гибких макетов.
Height и Width
Свойства Height и Width позволяют определить размер элемента. Можно использовать статические значения, измеренные в эффективных пикселях, функцию автоматического выбора размера либо пропорциональный размер.
Функция автоматического выбора размера позволяет изменяет размер элементов пользовательского интерфейса в соответствии с их содержимым или размером родительского контейнера. Можно также использовать функцию автоматического выбора размера со строками и столбцами сетки. Для использования функции автоматического выбора размеров установите для параметров Height и/или Width элементов пользовательского интерфейса значение Auto.
Примечание
Будет ли элемент изменять размер согласно своему содержимому или контейнеру, зависит от того, как родительский контейнер обработает изменение размеров его дочерних элементов. Дополнительные сведения см. в разделе Панели макета далее в этой статье.
Пропорциональное изменение размеров, которое задается символом звездочки, распределяет доступное пространство среди строк и столбцов сетки с помощью взвешенных пропорций. В XAML star значения выражаются как * (или n* для взвешиваемого star размера). Например, чтобы указать, что один столбец в 5 раз шире, чем второй столбец в макете с 2 столбцами, используйте "5*" и "*" для свойств Width в элементах ColumnDefinition .
В этом примере сочетаются фиксированный, автоматический и пропорциональный размер в элементе Grid с четырьмя столбцами.
Столбец | Определение размера | Описание |
---|---|---|
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, чтобы определить значения, которые ограничивают размер элемента, но в то же время обеспечивают его гибкое изменение.
В элементах Grid свойство MinWidth/MaxWidth можно также использовать с определениями столбца. Свойство MinHeight/MaxHeight можно использовать с определениями строки.
Выравнивание
Используйте свойства HorizontalAlignment и VerticalAlignment, чтобы указать, как элемент должен быть расположен в выделенном родительском контейнере.
- Значения для HorizontalAlignment: Left, Center, Right и Stretch.
- Значения для VerticalAlignment: Top, Center, Bottom и Stretch.
При выравнивании Stretch элементы занимают все выделенное им место в родительском контейнере. Stretch является значением по умолчанию для обоих свойств выравнивания. Однако некоторые элементы управления, например Button, перезаписывают это значение в своем стиле по умолчанию. Любой элемент, который может содержать дочерние элементы, может интерпретировать значение Stretch только для свойств HorizontalAlignment и VerticalAlignment. Например, элемент, использующий значения Stretch по умолчанию в Grid, растягивается, заполняя ячейку, которая его содержит. Тот же элемент, помещенный в Canvas, принимает размеры его содержимого. Подробнее о том, как каждая панель обрабатывает значение Stretch, см. в статье Панели макета.
Подробнее см. в статье Выравнивание, поле и заполнение и на справочных страницах HorizontalAlignment и VerticalAlignment.
Видимость
Вы можете показать или скрыть элемент, задав свойству Visibility одно из значений перечисления Visibility: Visible или Collapsed. Когда элемент свернут (Collapsed), он не занимает место в макете пользовательского интерфейса.
Можно изменить свойство Visibility элемента в коде или в визуальном состоянии. Когда свойство Visibility элемента изменено, все его дочерние элементы также изменяются. Вы можете заменить разделы своего пользовательского интерфейса путем отображения одной панели и сворачивания другой.
Совет
Если в пользовательском интерфейсе есть элементы, которые свернуты (Collapsed) по умолчанию, объекты продолжают создаваться при запуске, даже если они невидимы. Вы можете отложить загрузку этих элементов до их отображения с помощью атрибута x:Load , чтобы отложить создание объектов. Это может улучшить производительность при запуске. Дополнительные сведения см. в разделе Атрибут x:Load.
Ресурсы стиля
Вам не придется задавать значения свойства по отдельности для элемента управления. Обычно такой способ более эффективен для группировки значений свойств в ресурс Style и применения Style к элементу управления. Это в первую очередь касается случаев, когда необходимо применить одинаковые значения свойства к многочисленным элементам управления. Подробнее об использовании стилей см. в разделе Настройка стиля элементов управления.
Панели макета
Чтобы разместить видимые объекты, необходимо поместить их в элемент «Панель» или в другой объект-контейнер. Платформа XAML предоставляет различные классы panel, такие как Canvas, Grid, RelativePanel и StackPanel, которые служат контейнерами для размещения элементов пользовательского интерфейса.
Выбирая панель, главное — определить, как панель размещает свои дочерние элементы и задает их размеры. Также может потребоваться учесть характер перекрытия дочерних элементов, наложенных друг на друга.
Ниже показано сравнение основных функций элементов управления панели, предоставленных в платформе XAML.
Элемент управления панели | Описание |
---|---|
Canvas | Canvas не поддерживает гибкий пользовательский интерфейс; вы управляете всеми аспектами размещения и изменения размера дочерних элементов. Он обычно применяется в особых случаях, например, при создании графики или определении небольших статических областей большего адаптивного пользовательского интерфейса. Вы можете использовать код или визуальные состояния для перемещения элементов во время выполнения. |
Grid | 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 требовали объектов Storyboard для изменения свойств, и необходимо было вызвать GoToState в коде для применения состояния. Это демонстрируется в предыдущем примере. Вы увидите много примеров, которые также используют этот синтаксис. Возможно, у вас даже есть код, в котором он используется.
Начиная c Windows 10, можно использовать упрощенный синтаксис Setter, показанный здесь, и использовать объекты StateTrigger в разметке XAML для применения состояния. Триггеры состояния используется для создания своих простых правил, которые автоматически вызывают изменения визуального состояния в ответ на события приложения.
В этом примере выполняются те же действия, что и в предыдущем, но используется упрощенный синтаксис Setter вместо Storyboard для определения изменений свойств. И вместо вызова 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 является присоединенным к первому дочернему элементу корня, чтобы триггеры запускались автоматически. (Здесь Grid — это первый дочерний элемент корня Page).
Синтаксис присоединенного свойства
В 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 см. в разделе Пример триггеров состояния.
Визуальные состояния и стили
Ресурсы Style можно использовать в визуальных состояниях для применения набора изменений свойств к нескольким элементам управления. Подробнее об использовании стилей см. в разделе Настройка стиля элементов управления.
В этом упрощенном коде XAML из раздела "Пример триггеров состояния" ресурс Style применяется к Button для настройки размера и полей для ввода мышью или сенсорного ввода. Полный код и определение пользовательского триггера состояния см. в разделе Пример триггеров состояния.
<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
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по