UWP的一種下拉刷新實現


簡介

我們最近實現了一個在UWP中使用的下拉刷新功能,以滿足用戶的需求,因為這是下拉刷新是一種常見的操作方式,而UWP本身並不提供這一機制。

通過下拉刷新這一機制,可以讓移動端的界面設計變得更加簡單,更符合廣大用戶的使用習慣。

 

NEW github鏈接:https://github.com/MS-UAP/PullToRefresh.UWP

該組件的nuget鏈接:https://www.nuget.org/packages/PullToRefresh.UWP

 

並且,我們實現的這一下拉刷新功能,具有以下優點:

  • 支持自定義下拉頭部,包括及時顯示下拉進度,分辨率較高。
  • 用於ListView時,支持UI虛擬化和增量加載,不影響諸如ListView.Header等屬性。

 

基本使用

使用效果如圖:

只需要簡單的:

<pr:PullToRefreshBox x:Name="pr" RefreshInvoked="PullToRefreshBox_RefreshInvoked">
    <ListView x:Name="lv" ItemTemplate="{StaticResource ColorfulRectangle}" />
</pr:PullToRefreshBox>

這是默認的效果。用戶只需要訂閱 RefreshInvoked 事件即可。

該事件類型為:TypedEventHandler<DependencyObject, object>,第一個參數senderPullToRefreshBoxContent,第二個參數總是null

 

更多設置

我們的下拉刷新控件提供更多設置可供開發者自定義其表現。

  • double RefreshThreshold {get;set;} :設置觸發刷新的閾值,即有效下拉距離。
  • DataTemplate TopIndicatorTemplate {get;set;} :自定義下拉頭部模板。這是一個DataTemplate,其DataContext只是一個double值,表示相對於下拉閾值的百分比(可以超過100%)。而該模板本身會決定可用的下拉大小。

 同時,我們還提供了一個PullRefreshProgressControl控件,方便開發者進行簡單的頭部定制。

該控件提供兩個VisualState:Normal和ReleaseToRefresh,表示下拉過程中的兩種狀態(未到達刷新閾值,和已到達閾值)。

通過定義PullRefreshProgressControl.Template可以使用它(同樣也要設定一下PullToRefreshBox.TopIndicatorTemplate,並且對PullRefreshProgressControl.Progress屬性進行綁定)。

 

接下來為大家展示一下簡單的定制效果:

相關代碼如下:

<Grid>
    <pr:PullToRefreshBox RefreshInvoked="pr_RefreshInvoked">
        <pr:PullToRefreshBox.TopIndicatorTemplate>
            <DataTemplate>
                <Grid Background="LightBlue"
                      Height="130"
                      Width="200">
                    <pr:PullRefreshProgressControl Progress="{Binding}"
                                                   HorizontalAlignment="Center"
                                                   VerticalAlignment="Bottom">
                        <pr:PullRefreshProgressControl.Template>
                            <ControlTemplate>
                                <Grid>
                                    <VisualStateManager.VisualStateGroups>
                                        <VisualStateGroup x:Name="VisualStateGroup">
                                            <VisualState x:Name="Normal" />
                                            <VisualState x:Name="ReleaseToRefresh">
                                                <Storyboard>
                                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="txt" Storyboard.TargetProperty="Text">
                                                        <DiscreteObjectKeyFrame KeyTime="0" Value="釋放刷新" />
                                                    </ObjectAnimationUsingKeyFrames>
                                                </Storyboard>
                                            </VisualState>
                                        </VisualStateGroup>
                                    </VisualStateManager.VisualStateGroups>

                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="auto" />
                                        <RowDefinition Height="auto" />
                                    </Grid.RowDefinitions>

                                    <TextBlock x:Name="txt"
                                               Text="下拉刷新"
                                               Grid.Row="1"
                                               FontSize="20"
                                               HorizontalAlignment="Center" />
                                    <TextBlock Text="{Binding}"
                                               FontSize="24"
                                               Foreground="Gray"
                                               HorizontalAlignment="Center" />

                                </Grid>
                            </ControlTemplate>
                        </pr:PullRefreshProgressControl.Template>
                    </pr:PullRefreshProgressControl>

                </Grid>

            </DataTemplate>
        </pr:PullToRefreshBox.TopIndicatorTemplate>

        <ListView x:Name="ic">
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="HorizontalAlignment" Value="Center" />
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Rectangle Width="100" Height="200">
                        <Rectangle.Fill>
                            <SolidColorBrush Color="{Binding}" />
                        </Rectangle.Fill>
                    </Rectangle>
                </DataTemplate>
            </ListView.ItemTemplate>

        </ListView>
    </pr:PullToRefreshBox>
</Grid>

 

如果想要更加復雜的效果,則需要完全自定義PullToRefreshBox.TopIndicatorTemplate。

 

實現原理

采用外部嵌套ScrollViewer的方式實現。同時監控ScrollViewer的大小變化,以調整Content(即PullToRefreshBox.Content)的大小。

同時在下拉發生后,通過DirectManipulationCompleted事件,確定松開手指的時刻,並將下拉頭部滾出ScrollViewer的可視區域。

在ScrollViewer.ViewChanged事件中計算下拉距離,以實現分辨率較高的進度綁定。

 

已知問題

  • 用於StackPanel,Canvas這類有無限大空間的控件 且不指定PullToRefreshBox的具體大小時,其大小會恆定不變,而不會隨Content大小變化而變化。

 

該組件的nuget鏈接:https://www.nuget.org/packages/PullToRefresh.UWP

如果大家在使用中遇到了什么問題,希望能向我們反饋,以使得我們的實現變得更好。 

 

感謝 h82258652 提出的意見!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM