zoukankan      html  css  js  c++  java
  • Windows Runtime ListView 下拉刷新功能实现

    概述

    在Windows Runtime下,由于ListView控件没有提供任何有关此功能的方法事件,但是很多场景需要用到这方面的功能,所以在此记录下我的实现过程。

    基本思路:

    1.修改ListView控件模板,加入我们需要在下拉刷新时显示的提示文字或图片。同时加入一个位置指示元素,用于对下拉的高度进行定位。

    2.后台代码中加入一个定时器,用于检测是否发生下拉动作。

    修改ListView控件模板

    ListView控件模板修改如下,修改部分代码已做标记。

    对于下拉过程中的显示效果,可以根据各自的需要进行修改。

    <Style x:Key="SupportedPullDownListViewStyle" TargetType="ListView">
        <Setter Property="IsTabStop" Value="False"/>
        <Setter Property="Padding" Value="0"/>
        <Setter Property="TabNavigation" Value="Once"/>
        <Setter Property="IsSwipeEnabled" Value="True"/>
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        <Setter Property="VerticalContentAlignment" Value="Top"/>
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
        <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled"/>
        <Setter Property="ScrollViewer.VerticalScrollMode" Value="Enabled"/>
        <Setter Property="ScrollViewer.ZoomMode" Value="Disabled"/>
        <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False"/>
        <Setter Property="ScrollViewer.BringIntoViewOnFocusChange" Value="True"/>
        <Setter Property="ItemContainerTransitions">
            <Setter.Value>
                <TransitionCollection>
                    <AddDeleteThemeTransition/>
                    <ReorderThemeTransition/>
                </TransitionCollection>
            </Setter.Value>
        </Setter>
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <ItemsStackPanel Orientation="Vertical"/>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListView">
                    <Border BorderBrush="{TemplateBinding BorderBrush}" 
                            BorderThickness="{TemplateBinding BorderThickness}" 
                            Background="{TemplateBinding Background}">
                        <VisualStateManager.VisualStateGroups>
                            <!-- 定义下拉时的三种VisualState -->
                            <!-- CommonState: 未发生下拉动作 -->
                            <!-- PullDownState: 发生下拉动作,释放后不进行刷新 -->
                            <!-- PullDownHoldedState: 发生下拉动作,并且保持了一定时间,释放后立即刷新 -->
                            <VisualStateGroup x:Name="PullDownStates">
                                <VisualState x:Name="CommonState"></VisualState>
                                <VisualState x:Name="PullDownState">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PullDownArrow"
                                                                       Storyboard.TargetProperty="UIElement.Visibility">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                        </ObjectAnimationUsingKeyFrames>
    
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PullDownText"
                                                                       Storyboard.TargetProperty="UIElement.Visibility">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="PullDownHoldedState">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PullDownArrow"
                                                                       Storyboard.TargetProperty="UIElement.Visibility">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                        </ObjectAnimationUsingKeyFrames>
    
                                        <DoubleAnimationUsingKeyFrames Storyboard.TargetName="PullDownArrow"
                                                                       Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)">
                                            <EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="-180"/>
                                        </DoubleAnimationUsingKeyFrames>
    
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PullDownedText"
                                                                       Storyboard.TargetProperty="UIElement.Visibility">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <!-- 定义下拉VisualState结束 -->
                        </VisualStateManager.VisualStateGroups>
    
                        <Grid x:Name="PullDownGridContainer">
                            <!-- 定义下拉时显示的文字及箭头图形 -->
                            <StackPanel Orientation="Horizontal"
                                        Height="30"
                                        Margin="0,15"
                                        VerticalAlignment="Top"
                                        HorizontalAlignment="Center">
                                <Path Data="M 0,3 L 2,5 L 2,0 M 2,5 L 4,3"
                                      Stroke="#FF514E4E"
                                      StrokeThickness="1"
                                      Stretch="Uniform"
                                      Height="20"
                                      Visibility="Collapsed"
                                      x:Name="PullDownArrow"
                                      RenderTransformOrigin="0.5,0.5">
                                    <Path.RenderTransform>
                                        <RotateTransform Angle="0"/>
                                    </Path.RenderTransform>
                                </Path>
                                <TextBlock Margin="10,0,0,0"
                                           Foreground="#FF514E4E"
                                           x:Name="PullDownText"
                                           VerticalAlignment="Center"
                                           HorizontalAlignment="Center"
                                           FontSize="18"
                                           Visibility="Collapsed"
                                           FontWeight="Light">
                                    下拉刷新
                                </TextBlock>
                                <TextBlock Margin="10,0,0,0"
                                           x:Name="PullDownedText"
                                           Foreground="#FF514E4E"
                                           VerticalAlignment="Center"
                                           HorizontalAlignment="Center"
                                           FontSize="18"
                                           Visibility="Collapsed"
                                           FontWeight="Light">
                                    释放立即刷新
                                </TextBlock>
                            </StackPanel>
                            <!-- 定义结束 -->
                            <ScrollViewer x:Name="ScrollViewer" AutomationProperties.AccessibilityView="Raw" 
                                          BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}"
                                          HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" 
                                          HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" 
                                          IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" 
                                          IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}" 
                                          IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}" 
                                          IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" 
                                          IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" 
                                          TabNavigation="{TemplateBinding TabNavigation}" 
                                          VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" 
                                          VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
                                          ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
                                <StackPanel>
                                    <!-- 定义下拉位置指示元素 -->
                                    <Grid x:Name="PullDownGridIndicator">
                                    </Grid>
                                    <!-- 定义结束 -->
                                    <ItemsPresenter FooterTransitions="{TemplateBinding FooterTransitions}" 
                                                    FooterTemplate="{TemplateBinding FooterTemplate}" 
                                                    Footer="{TemplateBinding Footer}" 
                                                    HeaderTemplate="{TemplateBinding HeaderTemplate}" 
                                                    Header="{TemplateBinding Header}" 
                                                    HeaderTransitions="{TemplateBinding HeaderTransitions}"
                                                    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                    Padding="{TemplateBinding Padding}"
                                                    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                                </StackPanel>
                            </ScrollViewer>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    下拉状态状态转换

    由于在Xaml文件中定义了ListView的三种VisualState,所以需要在后台代码中实现这三种状态的切换。

    可以看到,VisualState属性表示ListView当前的状态,在切换到PullDownState状态时,同时记录下切换的时间。该时间用于之后判断是否切换到PullDownHoldedState状态。

    /// <summary>
    /// 发生下拉动作的时间
    /// </summary>
    private DateTime PullDownStartTime { get; set; }
    
    private enum PullDownVisualState
    {
        CommonState,
    
        PullDownState,
    
        PullDownHoldedState,
    }
    
    private PullDownVisualState _VisualState = PullDownVisualState.CommonState;
    
    private PullDownVisualState VisualState
    {
        get { return _VisualState; }
        set
        {
            if (_VisualState != value)
            {
                _VisualState = value;
    
                if (_VisualState == PullDownVisualState.CommonState)
                {
                    VisualStateManager.GoToState(SupportedPullDownListView, "CommonState", false);
                }
                else if (_VisualState == PullDownVisualState.PullDownState)
                {
                    PullDownStartTime = DateTime.Now;
    
                    VisualStateManager.GoToState(SupportedPullDownListView, "PullDownState", false);
                }
                else if (_VisualState == PullDownVisualState.PullDownHoldedState)
                {
                    VisualStateManager.GoToState(SupportedPullDownListView, "PullDownHoldedState", false);
                }
            }
        }
    }

    下拉定时器

    在ListView滚动过程中,由于没有现成的事件可以调用,因此需要定义一个定时器用于监视滚动位置。

    PullDownTimer = new DispatcherTimer();
    PullDownTimer.Interval = TimeSpan.FromMilliseconds(100);
    PullDownTimer.Tick += PullDownTimer_Tick;
    PullDownTimer.Start();

    当定时超时时,进行位置检查。

    若发生下拉或释放动作,则进行状态切换。

    private async void PullDownTimer_Tick(object sender, object e)
    {
        // 获取位置指示元素相对于其容器的位置
        var elementBounds = PullDownIndicator.TransformToVisual(PullDownContainer).TransformBounds(new Rect(0.0, 0.0, PullDownContainer.ActualWidth, PullDownContainer.ActualHeight));
    
        if (elementBounds.Top > 60) // 此处的60代表下拉的阈值,可根据实际情况调整该值
        {
            if (VisualState == PullDownVisualState.CommonState)
            {
                VisualState = PullDownVisualState.PullDownState;
            }
            else if (VisualState == PullDownVisualState.PullDownState)
            {
                if (DateTime.Now - PullDownStartTime > TimeSpan.FromSeconds(1)) // 此处设定下拉保持时间为1秒,即下拉状态保持1秒后释放才有效,该值可根据实际情况调整
                {
                    VisualState = PullDownVisualState.PullDownHoldedState;
                }
            }
        }
        else
        {
            if (VisualState == PullDownVisualState.PullDownHoldedState)
            {
                // 执行刷新代码
            }
    
            VisualState = PullDownVisualState.CommonState;
        }
    }

    附,获取ListView控件模板中的元素

    建立帮助类,添加扩展方法

    public static class VisualTreeHelperExtension
    {
        public static T GetFirstDescendantOfType<T>(this DependencyObject start) where T : DependencyObject
        {
            return start.GetDescendantsOfType<T>().FirstOrDefault();
        }
    
        public static IEnumerable<T> GetDescendantsOfType<T>(this DependencyObject start) where T : DependencyObject
        {
            return start.GetDescendants().OfType<T>();
        }
    
        public static IEnumerable<DependencyObject> GetDescendants(this DependencyObject start)
        {
            if (start == null)
            {
                yield break;
            }
    
            var queue = new Queue<DependencyObject>();
            queue.Enqueue(start);
    
            while (queue.Count > 0)
            {
                var parent = queue.Dequeue();
    
                var popup = parent as Popup;
    
                if (popup != null)
                {
                    if (popup.Child != null)
                    {
                        queue.Enqueue(popup.Child);
                        yield return popup.Child;
                    }
                }
                else
                {
                    var count = VisualTreeHelper.GetChildrenCount(parent);
    
                    for (int i = 0; i < count; i++)
                    {
                        var child = VisualTreeHelper.GetChild(parent, i);
                        yield return child;
                        queue.Enqueue(child);
                    }
                }
            }
        }
    }

    例如需要获取位置指示元素,调用如下,其中ListView控件名为SupportedPullDownListView

    SupportedPullDownListView.GetDescendantsOfType<Grid>().FirstOrDefault(x => x.Name == "PullDownGridIndicator")
  • 相关阅读:
    Linux常用命令大全(非常全!!!)
    Springboot项目与vue项目整合打包
    Spring Boot开启Druid数据库监控功能
    (八)CXF添加自定义拦截器
    (七)CXF添加拦截器
    (六)cxf处理一些Map等复杂类型
    (无)webservice执行过程深入理解
    (四)CXF处理JavaBean以及复合类型
    (三)使用CXF开发WebService客户端
    (二)使用CXF开发WebService服务器端接口
  • 原文地址:https://www.cnblogs.com/tongqj/p/4781978.html
Copyright © 2011-2022 走看看