zoukankan      html  css  js  c++  java
  • 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 提出的意见!

  • 相关阅读:
    translations.dart阅读
    # objc-weak 阅读
    Objective-C Runtime2.0(-)
    iOS图文混排
    BestCoder Round #85 抽屉原理/贪心/质因数
    hdu 5763 Another Meaning KMP+DP(多校)
    hdu 5775 Bubble Sort 树状数组(多校)
    BestCoder Round #84
    hdu 5724 SG函数+状压(多校)
    hdu 5723 最小生成树+dfs (多校)
  • 原文地址:https://www.cnblogs.com/ms-uap/p/4814507.html
Copyright © 2011-2022 走看看