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


Гибкие макеты

Система макетов XAML обеспечивает автоматическое изменение размеров элементов, панелей макетов и визуальных состояний для создания адаптивного интерфейса. Благодаря гибкому макету ваше приложение будет прекрасно смотреться на экранах с различными размерами окна, разными разрешениями, плотностью пикселей и ориентацией. XAML также можно использовать для изменения положения, изменения размера, показа и скрытия или изменения архитектуры пользовательского интерфейса приложения, как описано в статье Методы создания адаптивного дизайна. В этой статье описано, как реализовывать гибкие макеты с помощью XAML.

Гибкие макеты со свойствами и панелями

Основа гибкого макета — это правильное применение свойств и панелей макета XAML для гибкого изменения положения, изменения размеров и адаптации содержимого.

Система макета XAML поддерживает как статические, так и гибкие макеты. В статическом макете вы задаете контролам явные размеры и позиции в пикселях. Когда пользователь изменяет разрешение или ориентацию устройства, пользовательский интерфейс не изменяется. Статические макеты могут быть обрезаны в разных форм-факторах и размерах экрана. Гибкие макеты, напротив, сжимаются, растягиваются и видоизменяются, адаптируясь к доступному на устройстве визуальному пространству.

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

В этой статье описано, как создать гибкий макет с помощью свойств и панелей макета XAML.

Свойства макета

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

Ниже приведены некоторые распространенные свойства макета и способы их использования для создания гибких макетов.

Высота и Ширина

Свойства Height и Width позволяют определить размер элемента. Можно использовать фиксированные значения, измеряемые в эффективных пикселях, или использовать автоматический или пропорциональный размер.

Функция автоматического выбора размера позволяет изменяет размер элементов пользовательского интерфейса в соответствии с их содержимым или размером родительского контейнера. Вы также можете использовать автоматическую настройку размера для строк и столбцов сетки. Чтобы использовать автоматическое изменение размера, задайте для высоты и (или) ширины элементов пользовательского интерфейса значение Auto.

Замечание

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

Пропорциональное изменение размеров, также называемое звёздным изменением размеров, распределяет доступное пространство среди строк и столбцов сетки с помощью взвешенных пропорций. В XAML значения звезд выражаются как * (или n* для взвешированного размера звезд). Например, чтобы указать, что один столбец в 5 раз шире второго столбца в макете с 2 столбцами, используйте "5*" и "*" для свойств Width в элементах ColumnDefinition.

Этот пример объединяет фиксированный, автоматический и пропорциональный размер в сетке с 4 столбцами.

колонна Размеры Description
Колонка_1 Автоматически Размер столбца будет соответствовать его содержимому.
Столбец_2 * После вычисления автоматических столбцов столбец получает часть оставшейся ширины. Column_2 будет вполовину уже, чем Column_4.
Столбец_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, /, MinHeight и MaxHeight можно задать, чтобы указать значения, ограничивающие размер элемента, позволяя его динамическое изменение.

В сетке minWidth/MaxWidth также можно использовать с определениями столбцов, а MinHeight/MaxHeight можно использовать с определениями строк.

Выравнивание

Используйте свойства HorizontalAlignment и VerticalAlignment, чтобы указать, как элемент должен размещаться в родительском контейнере.

  • Значения для HorizontalAlignment: Слева, По центру, Справа и Растянуть.
  • Значения для VerticalAlignment: Top, Center, Bottom и Stretch.

При выравнивании Stretch элементы заполняют все пространство, которое им предоставлено в рамках родительского контейнера. Stretch — это значение по умолчанию для обоих свойств выравнивания. Однако некоторые элементы управления, такие как Button, переопределяют это значение в их стиле по умолчанию. Любой элемент, который может содержать дочерние элементы, может обрабатывать значение Stretch для свойств HorizontalAlignment и VerticalAlignment уникальным образом. Например, элемент с использованием значений Stretch по умолчанию, помещенный в сетку, растягивается для заполнения ячейки, содержащей его. Тот же элемент в холсте изменяет размер в соответствии со своим содержимым. Дополнительные сведения о том, как каждая панель обрабатывает значение Stretch, см. в статье о панелях макета .

Дополнительные сведения см. в статье "Выравнивание, поля и заполнение", а также на страницах справки по горизонтальному выравниванию и вертикальному выравниванию.

Видимость

Можно отобразить или скрыть элемент, задав его свойство Видимости одному из значений перечисления Видимости: Видимый или Свернутый. Если элемент свернут, он не занимает места в макете пользовательского интерфейса.

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

Подсказка

Если в пользовательском интерфейсе есть элементы, которые свернуты (Collapsed) по умолчанию, объекты продолжают создаваться при запуске, даже если они невидимы. Вы можете отложить загрузку этих элементов до тех пор, пока они не будут показаны с помощью атрибута x:Load, чтобы отложить создание объектов. Это может повысить производительность запуска. Дополнительные сведения см. в атрибуте x:Load.

Ресурсы стиля

Вам не нужно задавать каждое значение свойства по отдельности в элементе управления. Обычно более эффективно группировать значения свойств в ресурс Style и применять Style к элементу управления. Это особенно верно, если необходимо применить одни и те же значения свойств ко многим элементам управления. Дополнительные сведения об использовании стилей см. в разделе "Стилизация элементов управления".

Панели макета

Чтобы разместить визуальные объекты, их необходимо поместить в панель или другой объект контейнера. Платформа XAML предоставляет различные классы панелей, такие как Canvas, Grid, RelativePanel и StackPanel, которые служат контейнерами и позволяют размещать и упорядочивать элементы пользовательского интерфейса в них.

Главное, что нужно учитывать при выборе панели макета, это то, как панель располагает и изменяет размеры дочерних элементов. Кроме того, может потребоваться рассмотреть, как перекрывающиеся дочерние элементы располагаются друг над другом.

Ниже приведено сравнение основных функций элементов управления панели, предоставляемых в платформе XAML.

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

    Начиная с 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 присоединяется к первому дочернему элементу корневого элемента, чтобы триггеры вступают в силу автоматически. (Здесь, Сетка является первым дочерним элементом корневой страницы .)

    Синтаксис присоединенного свойства

    В 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 для применения различных состояний в зависимости от семейства устройств, на которые выполняется приложение. Примеры того, как создавать пользовательские триггеры и использовать их для оптимизации UI в одном представлении 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>