Sdílet prostřednictvím


Táhněte pro obnovení

Funkce pull-to-refresh umožňuje uživateli posunutím dolů na seznam dát pomocí dotykového ovládání načíst další data. Funkce pull-to-refresh se na zařízeních s dotykovou obrazovkou běžně používá. Pomocí zde uvedených rozhraní API můžete implementovat aktualizaci na vyžádání do aplikace.

přetáhnout pro obnovení GIF animace

Je to správná kontrola?

Funkci pull-to-refresh použijte, když máte seznam nebo mřížku dat, která by uživatel mohl chtít pravidelně aktualizovat, a vaše aplikace bude pravděpodobně spuštěná na zařízeních s dotykovým ovládáním.

Můžete také použít RefreshVisualizer k vytvoření konzistentního prostředí aktualizace, které je vyvoláno jinými způsoby, například tlačítkem aktualizovat.

Aktualizace ovládacích prvků

Tažení pro obnovení je povoleno dvěma ovládacími prvky.

  • RefreshContainer – ContentControl, který poskytuje obálku pro prostředí pro aktualizaci na vyžádání obsahu. Zpracovává dotykové interakce a spravuje stav interního vizualizéru aktualizací.
  • RefreshVisualizer – zapouzdřuje vizualizaci aktualizace vysvětlenou v další části.

Hlavní ovládací prvek je RefreshContainer, který umístíte jako obálku kolem obsahu, který uživatel stáhne, aby se aktivovala aktualizace. RefreshContainer funguje jenom s dotykovým ovládáním, takže doporučujeme, abyste měli k dispozici i tlačítko pro aktualizaci pro uživatele, kteří nemají dotykové rozhraní. Tlačítko aktualizace můžete umístit na vhodné místo v aplikaci, a to buď na panelu příkazů, nebo v umístění blízko surface, které se aktualizuje.

Aktualizace vizualizace

Výchozí vizualizace aktualizace je kruhový ukazatel průběhu, který slouží ke komunikaci, kdy se má aktualizace spustit, a sledování průběhu aktualizace během jejího provádění. Vizualizér aktualizace má 5 stavů.

Vzdálenost, kterou uživatel musí stáhnout v seznamu, aby zahájil aktualizaci, se nazývá prahová hodnota . Vizualizér State je určen stavem stažení, jak se vztahuje k tomuto prahu. Možné hodnoty jsou obsaženy v RefreshVisualizerState výčtu.

Idle

Výchozí stav vizualizéru je nečinný. Uživatel nepracuje s refreshContainerem prostřednictvím dotykového ovládání a neprobíhá aktualizace.

Vizuálně neexistuje žádný důkaz vizualizéru aktualizace.

Interakce

Když uživatel přetáhne seznam ve směru určeném vlastností PullDirection, ale ještě před dosažením prahové hodnoty, je vizualizér ve stavu Interakce.

  • Pokud uživatel uvolní ovládací prvek v tomto stavu, vrátí se ovládací prvek do stavu Nečinnost.

    vytažením pro obnovení před prahovou hodnotou

    Vizuálně se ikona zobrazí jako zakázaná (60% neprůhlednost). Kromě toho se ikona otočí o jednu úplnou rotaci při akci posouvání.

  • Pokud uživatel přetáhne seznam za prahovou hodnotu, vizualizér přejde z Interakce do Čekající.

    tažením obnovte na hranici

    Vizuálně ikona změní svou neprůhlednost na 100% a pulsuje ve velikosti až na 150%, poté se během přechodu vrátí na velikost 100%.

Čekající

Když uživatel přetáhl seznam za prahovou hodnotu, vizualizér je ve stavu Čekající.

  • Pokud uživatel přesune seznam zpět nad prahovou hodnotu, aniž by jej uvolnil, vrátí se do stavu Interakce.
  • Pokud uživatel seznam uvolní, požadavek na aktualizaci je zahájen a přejde do stavu Aktualizace.

aktualizace při překročení prahové hodnoty pro obnovení

Ikona je vizuálně 100%, pokud jde o velikost a neprůhlednost. V tomto stavu ikona pokračuje v pohybu dolů s akcí posouvání, ale už se nebude otáčet.

Osvěžující

Když uživatel uvolní vizualizér za prahovou hodnotu, je ve stavu Obnovování.

Když je tento stav zadán, je vyvolána událost RefreshRequested. Toto je signál ke spuštění aktualizace obsahu aplikace. Argumenty události (RefreshRequestedEventArgs) obsahují objekt Deferral, ke kterému byste měli v obslužné rutině události získat přístup. Až váš kód provede aktualizaci, měli byste pak označit odklad jako dokončený.

Po dokončení aktualizace se vizualizér vrátí do stavu nečinnosti .

Ikona se vizuálně urovná zpět k prahové poloze a otočí se po dobu trvání aktualizace. Toto otáčení slouží k zobrazení průběhu aktualizace a nahrazuje se animací příchozího obsahu.

Pokukování

Když uživatel potáhne ve směru aktualizace z výchozí pozice, kde není povolena aktualizace, vizualizér vstoupí do stavu Náhled. K tomu obvykle dochází, když scrollViewer není na pozici 0, když uživatel začne stahovat.

  • Pokud uživatel uvolní ovládací prvek v tomto stavu, vrátí se ovládací prvek do stavu Nečinnost.

Směr tahu

Ve výchozím nastavení uživatel načítá seznam shora dolů, aby zahájil aktualizaci. Pokud máte seznam nebo mřížku s jinou orientací, měli byste změnit směr tahu aktualizačního kontejneru, aby odpovídal.

Vlastnost PullDirection přebírá jednu z těchto hodnot RefreshPullDirection: BottomToTop, TopToBottom, RightToLeftnebo LeftToRight.

Když změníte směr tažení, počáteční pozice ukazatele průběhu vizualizace se automaticky otočí tak, aby šipka začínala ve správné poloze pro směr tažení. V případě potřeby můžete změnit vlastnost RefreshVisualizer.Orientation, abyste přepsali automatické chování. Ve většině případů doporučujeme ponechat výchozí hodnotu Auto.

Implementovat funkci pull-to-refresh

Ikona galerie WinUI 3 Aplikace Galerie WinUI 3 obsahuje interaktivní příklady ovládacích prvků a funkcí WinUI. Získejte aplikaci z Microsoft Store nebo vyhledejte zdrojový kód na GitHub.

Pokud chcete do seznamu přidat funkcionalitu tažením pro obnovení, je potřeba provést jen několik kroků.

  1. Zabalte seznam do ovládacího prvku s názvem RefreshContainer.
  2. Zpracujte událost RefreshRequested pro aktualizaci obsahu.
  3. Volitelně můžete zahájit aktualizaci voláním RequestRefresh (například kliknutím na tlačítko).

Poznámka:

Můžete sami vytvořit objekt RefreshVisualizer. Doporučujeme však zabalit váš obsah do objektu RefreshContainer a použít RefreshVisualizer, který je poskytován vlastností RefreshContainer.Visualizer, a to i pro scénáře, kde není použito dotykové ovládání. V tomto článku předpokládáme, že vizualizátor se vždy získá z aktualizačního kontejneru.

Kromě toho pro usnadnění použijte členy RequestRefresh a RefreshRequested kontejneru aktualizace. refreshContainer.RequestRefresh() je ekvivalentní refreshContainer.Visualizer.RequestRefresh(), a oba buď vyvolají událost RefreshContainer.RefreshRequested, i událost RefreshVisualizer.RefreshRequested.

Žádost o aktualizaci

Kontejner aktualizace zpracovává dotykové interakce, aby uživatel aktualizoval obsah dotykem. Doporučujeme poskytovat další možnosti pro rozhraní bez dotykového ovládání, jako je tlačítko pro aktualizaci nebo hlasové ovládání.

Chcete-li zahájit aktualizaci, zavolejte metodu RequestRefresh.

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

Při volání RequestRefresh stav vizualizéru přejde přímo z Nečinnosti do Obnovování.

Zpracování žádosti o aktualizaci

Pokud chcete získat aktuální obsah v případě potřeby, zpracujte událost RefreshRequested. V obslužné rutině události budete potřebovat kód specifický pro vaši aplikaci, abyste získali nový obsah.

Argumenty události (RefreshRequestedEventArgs) obsahují objekt Deferral. Získejte ukazatel na odklad v obslužné rutině události. Jakmile váš kód pro provedení aktualizace dokončí svou činnost, označte odložení jako dokončené.

// 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();
    }
}

Reakce na změny stavu

V případě potřeby můžete reagovat na změny ve stavu vizualizéru. Pokud například chcete zabránit více žádostem o aktualizaci, můžete zakázat tlačítko aktualizace, zatímco se vizualizér aktualizuje.

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

Použití prvku ScrollViewer v kontejneru RefreshContainer

Poznámka:

Obsah RefreshContaineru musí být posuvný ovládací prvek, například ScrollViewer, GridView, ListView atd. Nastavení obsahu na ovládací prvek, jako je Grid, způsobí nedefinované chování.

Tento příklad ukazuje, jak používat funkci pull-to-refresh s rolovacím panelem.

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

    </ScrollViewer>
</RefreshContainer>

Přidání gesto táhnutí pro obnovení do ListView

Tento příklad ukazuje, jak použít funkci pull-to-refresh se zobrazením seznamu.

<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; }
}