• WPF实现QQ群文件列表动画(一)


      QQ群大家都用过,先看下目前QQ的群文件列表容器的效果:

      细心点大家就会发现,这玩意收缩和展开是带动画的,并不是很僵硬地直接收缩或者直接展开,毫无疑问,如果用WPF实现这样的效果,这里的最佳控件是Expander,WPF的Expander控件自带Collapse和Expand功能,但是用过Expander的人都知道,这玩意的Collapse或者Expand是瞬间完成的,找遍Expander所有的属性,没有发现能设置为动画伸缩的,于是想到它里面一探究竟。用Blend编辑样式如下图:

      通过Blend可以清楚地看到Expand的时候发生了什么,当它Expand的时候,把ExpandSite的Visibility改成了Visible,ExpandSite是什么呢,它就是Expander的ContentPresenter,即内容载体,难怪呢,Visibility是瞬间的,没有什么动画可言。

      看到这也许你会很失望,因为没法对Visibility这个属性做动画。是不是真的没有办法了呢,当然不是,没有条件,可以创造条件。想想能做动画的是什么,最直接的,高度,或者——Transform,那么,即使我能对单个Expander做动画伸缩,怎么保证其他的Expander能动画上下位移呢?现在有3个问题需要解决:

      1.如何去掉Expander本身的Expander和Collapse效果,因为自带的效果是单纯的设置Visibility,这个属性是没法做动画的

      2.如何对单个Expander做动画伸缩,也就是使用它的哪个属性做动画

      3.对某个Expander伸缩的时候如何让其他的Expander自动位移

    这三个问题解决了,那么这种效果就实现了。

    问题1的解决思路

      似乎这三个问题都涉及到了控件内部的一些逻辑,最直接的想法是写个类继承Expander,然后去override相关函数,我试过,没什么作用,即使不用调base的函数,该出现的还是会出现。如果我有源码,或者我会在Measure里做些什么,也许可以改动一些逻辑,可惜我不会,我只会改改样式什么的。于是我想到了继承和样式相结合——事实上这种办法很大程度上简化了控件的开发(相对于游离在VisualTree和LogicTree之间的程序员来说),因为Style能快速增减控件,但是实现的逻辑有限,而继承控件能轻易实现逻辑,但对于一些人来说,继承后再加个控件,在哪里加,位置、背景、Margin、BorderThickness如何这些都太TM难了,调试难度也不低,所以继承和样式结合,各取所优,利益最大化。这样的话,我可以写个样式,把IsExpanded触发的逻辑去掉,然后写个类继承Expander,在构造函数里找到这个样式并设置为自己的Style,那么第一个问题就解决了。

    问题2的解决思路

      我想选高度来做动画吧,收缩好办,变为0就可以了,展开呢,高度该变为多少呢,Expander的高度是Auto,也就是根据内容来的,内容有多高展开就有多高,DoubleAnimation的To只是一个Double,没法绑定,这条路似乎有点难度。那么我用变形效果做动画呢,收缩的时候Y轴缩放为0,展开的时候Y轴缩放为1,这样我根本不用关心Expander的高度具体是多少,这样一来,问题2也得到了解决。

    问题3的解决思路

      单个的Expander行为怎么去影响别人的行为呢,这似乎有点为难。其实也不难,选好容器就可以,你把它们放在Grid里肯定是不行的,Gird只提供行列和Margin,如果要我关联Expander的伸缩事件然后挨个去设行列或者margin,那是会死人的。很显然,StackPanel最适合不过了,StackPanel提供Children了自动占用空间的特性,当一个child的高度变小,其他控件是会跟着移动的。但是还有个问题,我是选Expander的变形来做动画,印象中控件的变形效果其实不是发生了真正的布局改变,所以还有一点要注意,就是使用LayoutTransform,这个变形效果是会影响到布局的,而这正是我想要的结果,这样一来,问题3也解决了。以下是效果图:

    以下是部分代码:

      1 <Setter Property="Template">
      2             <Setter.Value>
      3                 <ControlTemplate TargetType="{x:Type Expander}">
      4                     <ControlTemplate.Resources>
      5                         <Storyboard x:Key="STHide">
      6                             <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
      7                                                            Storyboard.TargetName="ExpandSite">
      8                                 <EasingDoubleKeyFrame KeyTime="0:0:0.2"
      9                                                       Value="0" />
     10                             </DoubleAnimationUsingKeyFrames>
     11                             <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)"
     12                                                            Storyboard.TargetName="ExpandSite">
     13                                 <EasingDoubleKeyFrame KeyTime="0:0:0.2"
     14                                                       Value="1" />
     15                             </DoubleAnimationUsingKeyFrames>
     16                         </Storyboard>
     17                         <Storyboard x:Key="STShow">
     18                             <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
     19                                                            Storyboard.TargetName="ExpandSite">
     20                                 <EasingDoubleKeyFrame KeyTime="0"
     21                                                       Value="0" />
     22                                 <EasingDoubleKeyFrame KeyTime="0:0:0.2"
     23                                                       Value="1" />
     24                             </DoubleAnimationUsingKeyFrames>
     25                             <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)"
     26                                                            Storyboard.TargetName="ExpandSite">
     27                                 <EasingDoubleKeyFrame KeyTime="0"
     28                                                       Value="0" />
     29                                 <EasingDoubleKeyFrame KeyTime="0:0:0.2"
     30                                                       Value="1" />
     31                             </DoubleAnimationUsingKeyFrames>
     32                         </Storyboard>
     33                     </ControlTemplate.Resources>
     34                     <Border BorderBrush="{TemplateBinding BorderBrush}"
     35                             BorderThickness="{TemplateBinding BorderThickness}"
     36                             Background="{TemplateBinding Background}"
     37                             CornerRadius="3"
     38                             SnapsToDevicePixels="true">
     39                         <DockPanel>
     40                             <ToggleButton x:Name="HeaderSite"
     41                                           ContentTemplate="{TemplateBinding HeaderTemplate}"
     42                                           ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}"
     43                                           Content="{TemplateBinding Header}"
     44                                           DockPanel.Dock="Top"
     45                                           Foreground="{TemplateBinding Foreground}"
     46                                           FontWeight="{TemplateBinding FontWeight}"
     47                                           FocusVisualStyle="{StaticResource ExpanderHeaderFocusVisual}"
     48                                           FontStyle="{TemplateBinding FontStyle}"
     49                                           FontStretch="{TemplateBinding FontStretch}"
     50                                           FontSize="{TemplateBinding FontSize}"
     51                                           FontFamily="{TemplateBinding FontFamily}"
     52                                           HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
     53                                           IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
     54                                           Margin="1"
     55                                           MinWidth="0"
     56                                           MinHeight="0"
     57                                           Padding="{TemplateBinding Padding}"
     58                                           Style="{StaticResource ExpanderDownHeaderStyle}"
     59                                           VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
     60                             <ContentPresenter x:Name="ExpandSite"
     61                                               DockPanel.Dock="Bottom"
     62                                               Focusable="false"
     63                                               HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
     64                                               Margin="{TemplateBinding Padding}"
     65                                               Visibility="Visible"
     66                                               VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
     67                                 <ContentPresenter.LayoutTransform>
     68                                     <TransformGroup>
     69                                         <ScaleTransform />
     70                                         <SkewTransform />
     71                                         <RotateTransform />
     72                                         <TranslateTransform />
     73                                     </TransformGroup>
     74                                 </ContentPresenter.LayoutTransform>
     75                             </ContentPresenter>
     76                         </DockPanel>
     77                     </Border>
     78                     <ControlTemplate.Triggers>
     79                         <EventTrigger RoutedEvent="FrameworkElement.Loaded">
     80                             <BeginStoryboard Storyboard="{StaticResource STHide}" />
     81                         </EventTrigger>
     82                         <EventTrigger RoutedEvent="Expander.Expanded">
     83                             <BeginStoryboard x:Name="STShow_BeginStoryboard"
     84                                              Storyboard="{StaticResource STShow}" />
     85                         </EventTrigger>
     86                         <EventTrigger RoutedEvent="Expander.Collapsed">
     87                             <BeginStoryboard Storyboard="{StaticResource STHide}" />
     88                         </EventTrigger>
     89                         <Trigger Property="ExpandDirection"
     90                                  Value="Right">
     91                             <Setter Property="DockPanel.Dock"
     92                                     TargetName="ExpandSite"
     93                                     Value="Right" />
     94                             <Setter Property="DockPanel.Dock"
     95                                     TargetName="HeaderSite"
     96                                     Value="Left" />
     97                             <Setter Property="Style"
     98                                     TargetName="HeaderSite"
     99                                     Value="{StaticResource ExpanderRightHeaderStyle}" />
    100                         </Trigger>
    101                         <Trigger Property="ExpandDirection"
    102                                  Value="Up">
    103                             <Setter Property="DockPanel.Dock"
    104                                     TargetName="ExpandSite"
    105                                     Value="Top" />
    106                             <Setter Property="DockPanel.Dock"
    107                                     TargetName="HeaderSite"
    108                                     Value="Bottom" />
    109                             <Setter Property="Style"
    110                                     TargetName="HeaderSite"
    111                                     Value="{StaticResource ExpanderUpHeaderStyle}" />
    112                         </Trigger>
    113                         <Trigger Property="ExpandDirection"
    114                                  Value="Left">
    115                             <Setter Property="DockPanel.Dock"
    116                                     TargetName="ExpandSite"
    117                                     Value="Left" />
    118                             <Setter Property="DockPanel.Dock"
    119                                     TargetName="HeaderSite"
    120                                     Value="Right" />
    121                             <Setter Property="Style"
    122                                     TargetName="HeaderSite"
    123                                     Value="{StaticResource ExpanderLeftHeaderStyle}" />
    124                         </Trigger>
    125                         <Trigger Property="IsEnabled"
    126                                  Value="false">
    127                             <Setter Property="Foreground"
    128                                     Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
    129                         </Trigger>
    130                     </ControlTemplate.Triggers>
    131                 </ControlTemplate>
    132             </Setter.Value>
    133         </Setter>
    View Code

      这个样式主要是用过LayoutTransform下的ScaleTransForm做了伸缩动画,然后关联Expanded和Collapsed事件执行动画。

    1   <EventTrigger RoutedEvent="Expander.Expanded">
    2                             <BeginStoryboard x:Name="STShow_BeginStoryboard"
    3                                              Storyboard="{StaticResource STShow}" />
    4                         </EventTrigger>
    5                         <EventTrigger RoutedEvent="Expander.Collapsed">
    6                             <BeginStoryboard Storyboard="{StaticResource STHide}" />
    7                         </EventTrigger>
    View Code

      到这里似乎不需要再写个继承类来实现什么逻辑了,的确,这样的功能一个样式就搞定了,不过这里面有个缺陷,至于是什么缺陷,有什么办法弥补,将在下一篇阐述,敬请期待。

      本篇源码已在QQ群里共享,如有需要可以下载来研究。

  • 相关阅读:
    前端使用crypto.js进行加密
    C#编程总结(七)数据加密——附源码
    PID file /run/zabbix/zabbix_server.pid not readable (yet?) after start. 报错解决
    TNS-12560: Message 12560 not found; No message file for product=network, facility=TNS报错
    oracle无法启动asm实例记录
    linux添加硬盘分区挂载教程
    Oracle Database 12c Release 2安装过程实录
    Centos6.9minimal版系统安装图形化界面
    扫描工具nmap介绍
    Zabbix系列之六——添加web监测
  • 原文地址:https://www.cnblogs.com/zoexia/p/4264960.html
Copyright © 2020-2023  润新知