Поделиться через


Гибкие макеты на основе 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 результат выглядит следующим образом.

Сетка столбцов 4 в конструкторе 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 Холст не поддерживает гибкий пользовательский интерфейс; вы управляете всеми аспектами размещения и изменения размера дочерних элементов. Обычно он используется для специальных случаев, таких как создание графики или определение небольших статических областей более крупного адаптивного пользовательского интерфейса. Код или визуальные состояния можно использовать для изменения положения элементов во время выполнения.
  • Элементы размещаются абсолютно с помощью присоединенных свойств Canvas.Top и Canvas.Left.
  • Слои можно явно указать с помощью присоединенного свойства Canvas.ZIndex.
  • Значения stretch для HorizontalAlignment/VerticalAlignment игнорируются. Если размер элемента не задан явным образом, он имеет размер содержимого.
  • Дочернее содержимое визуально не обрезается, если больше панели.
  • Дочернее содержимое не ограничивается границами панели.
  • Сетка Grid поддерживает изменение размера дочерних элементов. Код или визуальные состояния можно использовать для изменения положения и перетека элементов.
  • Элементы упорядочивается в строках и столбцах с помощью присоединенных свойств Grid.Row и Grid.Column.
  • Элементы могут охватывать несколько строк и столбцов с помощью присоединенных свойств Grid.RowSpan и Grid.ColumnSpan.
  • Значения растяжения для HorizontalAlignment/VerticalAlignment учитываются. Если размер элемента не задан явным образом, он растягивается, чтобы заполнить доступное пространство в ячейке сетки.
  • Дочернее содержимое визуально обрезается, если больше панели.
  • Размер содержимого ограничен границами панели, поэтому при необходимости прокручиваемое содержимое отображает полосы прокрутки.
  • RelativePanel
  • Элементы упорядочены по краю или центру панели, а также по отношению друг к другу.
  • Элементы позиционируются с помощью различных присоединенных свойств, которые определяют выравнивание панели управления, выравнивание с братом и положение сестер.
  • Значения растяжения для HorizontalAlignment/VerticalAlignment игнорируются, если только присоединенные свойства RelativePanel для выравнивания вызывают растяжение (например, элемент выравнивается как по правому, так и левому краям панели). Если размер элемента не задан явным образом, и он не растянут, он размеров содержимого.
  • Дочернее содержимое визуально обрезается, если больше панели.
  • Размер содержимого ограничен границами панели, поэтому при необходимости прокручиваемое содержимое отображает полосы прокрутки.
  • StackPanel
  • Элементы стекаются в одну линию по вертикали или по горизонтали.
  • Значения stretch для HorizontalAlignment/VerticalAlignment учитываются в направлении, противоположном свойству Orientation. Если размер элемента не задан явным образом, он растягивается для заполнения доступной ширины (или высоты, если ориентация является горизонтальной). В направлении, указанном свойством Orientation, размер элемента в его содержимом.
  • Дочернее содержимое визуально обрезается, если больше панели.
  • Размер содержимого не ограничивается границами панели в направлении, указанном свойством ориентации, поэтому прокручиваемое содержимое простирается за пределы панели и не отображает полосы прокрутки. Для отображения полос прокрутки необходимо явно ограничить высоту (или ширину) дочернего содержимого.
  • VariableSizedWrapGrid
  • Элементы упорядочивается в строках или столбцах, которые автоматически упаковываются в новую строку или столбец при достижении значения MaximumRowsOrColumns.
  • Упорядочены ли элементы в строках или столбцах в свойстве Orientation.
  • Элементы могут охватывать несколько строк и столбцов с помощью присоединенных свойств VariableSizedWrapGrid.RowSpan и VariableSizedWrapGrid.ColumnSpan.
  • Значения stretch для HorizontalAlignment и VerticalAlignment игнорируются. Элементы имеют размер, указанный свойствами ItemHeight и ItemWidth. Если эти свойства не заданы, они получают значения на основе размера первой ячейки.
  • Дочернее содержимое визуально обрезается, если больше панели.
  • Размер содержимого ограничен границами панели, поэтому при необходимости прокручиваемое содержимое отображает полосы прокрутки.
  • Подробные сведения и примеры этих панелей см . на панелях макета.

    Панели макета позволяют упорядочивать пользовательский интерфейс в логические группы элементов управления. При использовании их с соответствующими параметрами свойств вы получите некоторую поддержку автоматического изменения размера, изменения положения и перетекания элементов пользовательского интерфейса. Однако большинству макетов пользовательского интерфейса требуется дальнейшее изменение, если существуют значительные изменения размера окна. Для этого можно использовать визуальные состояния.

    Адаптивные макеты с визуальными состояниями и триггерами состояния

    Используйте визуальные состояния, чтобы внести значительные изменения в пользовательский интерфейс на основе размера окна или других изменений.

    Когда окно приложения увеличивается или сжимается за пределами определенного объема, может потребоваться изменить свойства макета для изменения положения, изменения размера, изменения потока, отображения или замены разделов пользовательского интерфейса. Вы можете определить различные визуальные состояния пользовательского интерфейса и применить их, когда ширина окна или высота окна пересекает указанное пороговое значение.

    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>