Прочитать на английском

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


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

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

GIF для обновления с помощью потягивания

Это правильный элемент управления?

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

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

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

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

  • RefreshContainer — ContentControl, предоставляющий оболочку для функции «pull-to-refresh». Он обрабатывает сенсорные взаимодействия и управляет состоянием внутреннего визуализатора обновления.
  • 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 не находится в начальной позиции, когда пользователь начинает перетаскивать.

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

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

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

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

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

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

Приложение Галерея 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; }
}

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 />