簡介
我們最近實現了一個在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>,第一個參數sender為PullToRefreshBox的Content,第二個參數總是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 提出的意見!
