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


Потяните, чтобы обновить

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

GIF-анимация функции

Выбор правильного элемента управления

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

Также можно использовать RefreshVisualizer для создания согласованного обновления, вызываемого другими способами, например, с помощью кнопки "Обновить".

Обновить элементы управления

Функция "pull-to-refresh" активируется двумя элементами управления.

  • RefreshContainer — ContentControl, предоставляющий оболочку для процесса обновления. Он обрабатывает сенсорные взаимодействия и управляет состоянием внутреннего визуализатора обновления.
  • RefreshVisualizer — инкапсулирует визуализацию обновления, описанную в следующем разделе.

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

Визуализация обновления

Визуализация обновления по умолчанию — это циклический индикатор хода выполнения, который сообщает о том, когда произойдет обновление, и о ходе обновления после его запуска. Визуализатор обновления имеет 5 состояний.

Расстояние, на которое пользователь должен оттянуть список вниз для инициации обновления, называется threshold (пороговое значение). Визуализатор State определяется состоянием оттягивания в отношении этого порогового значения. Допустимые значения находятся в перечислении RefreshVisualizerState.

Бездействие

Состоянием визуализатора по умолчанию является Idle. Пользователь не взаимодействует с RefreshContainer посредством сенсорного ввода и обновление не выполняется.

Визуальные признаки работы визуализатора обновления отсутствуют.

Взаимодействие

Когда пользователь оттягивает список в направлении, заданном свойством PullDirection, и до достижения порогового значения, визуализатор находится в состоянии Interacting.

  • Если пользователь отпускает элемент управления в этом состоянии, он возвращается в состояние Idle.

    Состояние функции обновления путем оттягивания до достижения порогового значения

    Визуально значок отображается как отключенный (непрозрачность 60 %). Кроме того, значок производит один полный оборот с помощью действия прокрутки.

  • Если пользователь оттянет список, превысив значение порогового значения, визуализатор перейдет из состояния Interacting в состояние Pending.

    Состояние функции обновления путем оттягивания при достижении порогового значения

    Визуально прозрачность значка составит 100 % и он будет меняться в размере до 150 % и возвращаться обратно до 100 % во время процесса перехода состояний.

Не завершено

Когда пользователь оттягивает список, превысив пороговое значение, визуализатор переходит в состояние Pending.

  • Когда пользователь перемещает список обратно, в пределы порогового значения, не отпуская его, визуализатор переходит в состояние Interacting.
  • Если пользователь отпускает список, инициируется запрос на обновление и визуализатор переходит в состояние Refreshing.

Состояние функции обновления путем оттягивания после достижения порогового значения

Визуально размер и непрозрачность значка составляют 100 %. В этом состоянии значок продолжает перемещаться вниз с помощью действия прокрутки, но больше не вращается.

Обновление

Когда пользователь отпускает визуализатор за пределами порогового значения, он переходит в состояние Refreshing.

При входе в это состояние возникает событие RefreshRequested. Это сигнал для запуска обновления содержимого приложения. Аргументы события (RefreshRequestedEventArgs) содержат объект Deferral, который следует использовать в обработчике событий. Затем отсрочку следует пометить как завершенную, когда код для выполнения обновления завершится.

После завершения обновления визуализатор возвращается в состояние Idle.

Визуально значок возвращается обратно в пороговое положение и вращается на протяжении процесса обновления. Это вращение используется для отображения хода выполнения обновления и заменяется анимацией входящего содержимого.

Просмотр

Когда пользователь оттягивает список в направлении обновления из начального положения, где обновление не разрешено, визуализатор переходит в состояние Peeking. Как правило, это происходит, если элемент ScrollViewer не находится в положении 0, когда пользователь начинает оттягивать список.

  • Если пользователь отпускает элемент управления в этом состоянии, он возвращается в состояние Idle.

Направление оттягивания

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

Свойство PullDirection принимает одно из следующих значений RefreshPullDirection: BottomToTop, TopToBottom, RightToLeft или LeftToRight.

При изменении направления вытягивания начальная позиция спиннера хода выполнения визуализатора автоматически поворачивается, чтобы стрелка начиналось в соответствующей позиции для направления вытягивания. При необходимости можно изменить свойство RefreshVisualizer.Orientation, чтобы переопределить автоматическое поведение. В большинстве случаев мы рекомендуем оставлять значение по умолчанию Auto.

UWP и WinUI 2

Внимание

Сведения и примеры в этой статье оптимизированы для приложений, использующих пакет SDK для приложений Windows и WinUI 3, но обычно применимы к приложениям UWP, использующим WinUI 2. См. справочник по API UWP для конкретных сведений и примеров платформы.

В этом разделе содержатся сведения, необходимые для использования элемента управления в приложении UWP или WinUI 2.

Элементы управления обновления для приложений UWP включены в состав WinUI 2. Дополнительные сведения, включая инструкции по установке, см. в статье WinUI 2. API для этого элемента управления существуют в пространствах имен Windows.UI.Xaml.Controls (UWP) и Microsoft.UI.Xaml.Controls (WinUI).

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

Чтобы использовать код в этой статье с WinUI 2, используйте псевдоним в XAML (мы используем muxc), чтобы представить API библиотеки пользовательского интерфейса Windows, включенные в проект. Дополнительные сведения см. в статье "Начало работы с WinUI 2 ".

xmlns:muxc="using:Microsoft.UI.Xaml.Controls"

<muxc:RefreshContainer />

Реализация обновления по запросу

Приложение коллекции WinUI 3 включает интерактивные примеры большинства элементов управления, функций и функций WinUI 3. Получение приложения из Microsoft Store или получение исходного кода на GitHub

Чтобы добавить функцию обновления путем оттягивания в список, нужно выполнить всего несколько действий.

  1. Перенесите список в элемент управления RefreshContainer.
  2. Обработайте событие RefreshRequested для обновления содержимого.
  3. При необходимости запустите обновление, вызвав метод RequestRefresh (например, нажатием кнопки).

Примечание.

Можно создать отдельный экземпляр RefreshVisualizer. Тем не менее мы рекомендуем переносить содержимое в RefreshContainer и использовать RefreshVisualizer, предоставляемый свойством RefreshContainer.Visualizer даже для сценариев без сенсорного ввода. В этой статье мы предполагаем, что визуализатор всегда берется из контейнера обновления.

Кроме того, используйте члены контейнера обновления RequestRefresh и RefreshRequested для удобства. refreshContainer.RequestRefresh()эквивалентноrefreshContainer.Visualizer.RequestRefresh(), и любой из них вызовет как событие RefreshContainer.RefreshRequested, так и события RefreshVisualizer.RefreshRequested.

Запрос на обновление

Контейнер обновления обрабатывает сенсорные взаимодействия, позволяя пользователю обновить содержимое с помощью сенсорного ввода. Мы рекомендуем реализовывать другие возможности для интерфейсов без сенсорного ввода, например, кнопку "Обновить" или управление голосом.

Чтобы запустить обновление, вызовите метод RequestRefresh.

// See the Examples section for the full code.
private void RefreshButtonClick(object sender, RoutedEventArgs e)
{
    RefreshContainer.RequestRefresh();
}

При вызове RequestRefresh визуализатор напрямую переходит из состояния Idle в состояние Refreshing.

Обработка запроса на обновление

Чтобы получить обновленное содержимое, при необходимости, обработайте событие RefreshRequested. В обработчике событий, необходимо добавить код для конкретного приложения, чтобы получить обновленное содержимое.

Аргументы события (RefreshRequestedEventArgs) содержат объект Deferral. Получите дескриптор отсрочки в обработчике событий. Затем отсрочку следует пометить как завершенную, когда код завершил выполнение обновления.

// See the Examples section for the full code.
private async void RefreshContainer_RefreshRequested(RefreshContainer sender, RefreshRequestedEventArgs args)
{
    // Respond to a request by performing a refresh and using the deferral object.
    using (var RefreshCompletionDeferral = args.GetDeferral())
    {
        // Do some async operation to refresh the content

         await FetchAndInsertItemsAsync(3);

        // The 'using' statement ensures the deferral is marked as complete.
        // Otherwise, you'd call
        // RefreshCompletionDeferral.Complete();
        // RefreshCompletionDeferral.Dispose();
    }
}

Реагирование на изменения состояния

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

// See the Examples section for the full code.
private void Visualizer_RefreshStateChanged(RefreshVisualizer sender, RefreshStateChangedEventArgs args)
{
    // Respond to visualizer state changes.
    // Disable the refresh button if the visualizer is refreshing.
    if (args.NewState == RefreshVisualizerState.Refreshing)
    {
        RefreshButton.IsEnabled = false;
    }
    else
    {
        RefreshButton.IsEnabled = true;
    }
}

Использование ScrollViewer в RefreshContainer

Примечание.

Содержимое RefreshContainer должно быть прокручиваемым элементом управления, например ScrollViewer, GridView, ListView и т. д. Установка содержимого в элемент управления, например Grid, приведет к неопределенному поведению.

В этом примере показано, как использовать функцию обновления путем оттягивания со средством просмотра прокрутки.

<RefreshContainer>
    <ScrollViewer VerticalScrollMode="Enabled"
                  VerticalScrollBarVisibility="Auto"
                  HorizontalScrollBarVisibility="Auto">
 
        <!-- Scrollviewer content -->

    </ScrollViewer>
</RefreshContainer>

Добавление функции обновления путем оттягивания в ListView

В этом примере показано, как использовать функцию обновления путем оттягивания с представлением списка.

<StackPanel Margin="0,40" Width="280">
    <CommandBar OverflowButtonVisibility="Collapsed">
        <AppBarButton x:Name="RefreshButton" Click="RefreshButtonClick"
                      Icon="Refresh" Label="Refresh"/>
        <CommandBar.Content>
            <TextBlock Text="List of items" 
                       Style="{StaticResource TitleTextBlockStyle}"
                       Margin="12,8"/>
        </CommandBar.Content>
    </CommandBar>

    <RefreshContainer x:Name="RefreshContainer">
        <ListView x:Name="ListView1" Height="400">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:ListItemData">
                    <Grid Height="80">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <TextBlock Text="{x:Bind Path=Header}"
                                   Style="{StaticResource SubtitleTextBlockStyle}"
                                   Grid.Row="0"/>
                        <TextBlock Text="{x:Bind Path=Date}"
                                   Style="{StaticResource CaptionTextBlockStyle}"
                                   Grid.Row="1"/>
                        <TextBlock Text="{x:Bind Path=Body}"
                                   Style="{StaticResource BodyTextBlockStyle}"
                                   Grid.Row="2"
                                   Margin="0,4,0,0" />
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </RefreshContainer>
</StackPanel>
public sealed partial class MainPage : Page
{
    public ObservableCollection<ListItemData> Items { get; set; } 
        = new ObservableCollection<ListItemData>();

    public MainPage()
    {
        this.InitializeComponent();

        Loaded += MainPage_Loaded;
        ListView1.ItemsSource = Items;
    }

    private async void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        Loaded -= MainPage_Loaded;
        RefreshContainer.RefreshRequested += RefreshContainer_RefreshRequested;
        RefreshContainer.Visualizer.RefreshStateChanged += Visualizer_RefreshStateChanged;

        // Add some initial content to the list.
        await FetchAndInsertItemsAsync(2);
    }

    private void RefreshButtonClick(object sender, RoutedEventArgs e)
    {
        RefreshContainer.RequestRefresh();
    }

    private async void RefreshContainer_RefreshRequested(RefreshContainer sender, RefreshRequestedEventArgs args)
    {
        // Respond to a request by performing a refresh and using the deferral object.
        using (var RefreshCompletionDeferral = args.GetDeferral())
        {
            // Do some async operation to refresh the content

            await FetchAndInsertItemsAsync(3);

            // The 'using' statement ensures the deferral is marked as complete.
            // Otherwise, you'd call
            // RefreshCompletionDeferral.Complete();
            // RefreshCompletionDeferral.Dispose();
        }
    }

    private void Visualizer_RefreshStateChanged(RefreshVisualizer sender, RefreshStateChangedEventArgs args)
    {
        // Respond to visualizer state changes.
        // Disable the refresh button if the visualizer is refreshing.
        if (args.NewState == RefreshVisualizerState.Refreshing)
        {
            RefreshButton.IsEnabled = false;
        }
        else
        {
            RefreshButton.IsEnabled = true;
        }
    }

    // App specific code to get fresh data.
    private async Task FetchAndInsertItemsAsync(int updateCount)
    {
        for (int i = 0; i < updateCount; ++i)
        {
            // Simulate delay while we go fetch new items.
            await Task.Delay(1000);
            Items.Insert(0, GetNextItem());
        }
    }

    private ListItemData GetNextItem()
    {
        return new ListItemData()
        {
            Header = "Header " + DateTime.Now.Second.ToString(),
            Date = DateTime.Now.ToLongDateString(),
            Body = DateTime.Now.ToLongTimeString()
        };
    }
}

public class ListItemData
{
    public string Header { get; set; }
    public string Date { get; set; }
    public string Body { get; set; }
}

Получение кода примера

  • Пример коллекции WinUI. Просмотрите все элементы управления XAML в интерактивном формате.