WPF学习之--图形变形和动画概念总览
图形的变形(Transform)
控制变形的属性有2个:
RenderTransform呈现变形,定义在UIElement类中
LayoutTransform:布局变形,定义在FrameworkElement类中
Transform的派生类有以下几种,它们都可以作用于RenderTransform和LayoutTransform。
1.MatrixTransform:矩形变形
2.RotateTransform:旋转变形
3.ScaleTransform:坐标系变形,可产生缩放效果
4.SkewTransform:拉伸变形,可以在纵向和横向上对被变形元素进行拉伸
5.TranslateTransform:偏移变形
6.TransformGroup:变形组
一、呈现变形RenderTransform
呈现变形RenderTransform只改变元素“出现在哪里”,所以不牵扯布局的改变,一般用于动画。这么做的好处是提升效率。
<Button x:Name="jsj" Content="hggggg" Width="80" Margin="80"> <Button.RenderTransform> <TransformGroup> <RotateTransform CenterX="40" CenterY="40" Angle="45"/> <TranslateTransform X="100" Y="200"/> </TransformGroup> </Button.RenderTransform> </Button>
二、布局变形LayoutTransform
布局变形会影响窗体的布局,导致窗体布局的重新测算,而这会影响程序的性能,所以布局变形只用在静态变形上,而不用于制作动画。
<TextBlock Text="Hello Transform" FontSize="24" HorizontalAlignment="Left" VerticalAlignment="Bottom" Grid.Row="1"> <TextBlock.LayoutTransform> <RotateTransform Angle="-90"/> </TextBlock.LayoutTransform> </TextBlock>
二、动画
动画的本质是一个时间段内对象位置,角度,颜色,透明度的连续变化。这些属性中,有些是对象自身的属性,有些则是图形变形的属性,注意,制动动画的属性都是依赖属性。
分类:
1)线性插值
概念:这种动画是在开始值和结束值之间逐步增加的方式改变属性的动画,使用“类型名”+Animation方式命名。DoubleAnimation和ColorAnimation属于这类
某个元素属性值发生连续变化,任何一个属性都有自己的数据类型,针对每个可能的数据类型,wpf子系统都为其准备了相应的动画类,这些动画类
均派生自AnimationTimeLine,例如DoubleAnimationBase(以下以此为例),然后这些抽象基类又派生出3种具体动画,即简单动画,关键帧动画,沿路径运动动画。
1)简单线性动画,由以下4要素组成
1.变化时间(Duration):是在动画开始时刻和结束时刻之间的时间间隔。
2.变化终点(To属性)
3.变化幅度(By属性)
4.变化起点(From属性)
2)关键帧动画
概念:从一个值突然变成另一个值的动画,所有的关键帧动画都使用“类型名”+AnimationUsingKeyFrames形式命名,比如DoubleAnimationUsingKeyFrames类。
String和引用类型的对象,插值是没有意义的。
动画是UI元素属性连续变化所产生的视觉效果,属性每次细微的变化都会产生一个新的画面,每个新画面就称为“一帧”,帧的连续播放就会产生动画效果。
单位时间内播放的帧越多,动画效果越细致。
上述的简单动画只设置了起点和终点,之间的动画帧都是由程序计算出来并绘制的,程序员无法进行控制。
关键帧动画有4类
1.LinerDoubleKeyFrame;线性变化关键帧,目标属性变化是直线性的,均匀的
2.DiscreteDoubleKeyFrame:不连续变化关键帧,目标属性的变化是跳跃的
3.SplineDoubleKeyFrame:样条函数变化关键帧,目标属性的变化速率是一条贝塞尔曲线。
4.EasingDoubleKeyFrame:缓冲变化关键帧
3)路径动画
如:DoubleAnimationUsingPath类)
DoubleAnimationUsingPath需要一个PathGeometry来指明移动路径,PathGeometry的数据信息可以用XAML的Path语法书写。PathGeometry的另一个重要属性是Source。
三、Storyboard(故事板,场景)
Storyboard可以用来分组多个动画,
定义故事板:Storyboard类提供的最基本功能是能够使用TargetProperty和TargetName属性指向特定属性和特定元素,故事板在动画和希望应用动画的属性之间架起一座桥梁。
事件触发器:让故事板实际运行起来,需要有事件触发器。
有4个位置定义事件触发器
1)在样式中(Styles.Trigger集合)
2)在数据模板中(DataTemplate.Trigger集合)
3)在控件模板中(ControlTemplate.Trigger集合)
4)直接在元素中定义事件触发器(FrameworkElement集合)
示例1:Storyboard.TargetProperty属性指定希望改变的属性,如果没有指定Storyboard.TargetName属性时,故事板使用父类元素,该例中为按钮。[注意这种类型是:FrameworkElement.Trigger集合]
<Button Padding="10" Height="50" Width="50" Content="测试"> <Button.Triggers> <EventTrigger RoutedEvent="Button.Click"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard > <DoubleAnimation Storyboard.TargetProperty="Width" To="100" Duration="0:0:5"/> <DoubleAnimation Storyboard.TargetProperty="Height" To="100" Duration="0:0:5"/> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Button.Triggers> </Button>
该例中如果涉及到计算,可以通过IValueConverter接口实现。
示例2:除了事件触发器是关联动画的最常用方式,还可以使用样式,模板中的Trigger集合,通过他们可以创建当属性值发生变化时进行响应的属性触发器。
<Window.Resources> <Style x:Key="ButtonStyle"> <Style.Triggers> <Trigger Property="Button.IsPressed" Value="True"> <Trigger.EnterActions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Width" To="100" Duration="0:0:5"></DoubleAnimation> <DoubleAnimation Storyboard.TargetProperty="Height" To="100" Duration="0:0:5"></DoubleAnimation> </Storyboard> </BeginStoryboard> </Trigger.EnterActions> </Trigger> </Style.Triggers> </Style> </Window.Resources>
<Button Padding="-10" Height="50" Width="50" Content="测试2" Style="{StaticResource ButtonStyle}"/>
示例2中使用Trigger.EnterAction设置当属性改变到指定的数值时希望执行的动作(示例:当IsPressed属性变为true时),也可以使用Trigger.ExitAction设置属性改变回原来的数值时执行的动作(例如当IsPressed属性变为false)。
示例3是关键帧动画
<StackPanel Orientation="Vertical" Grid.Column="1"> <Border BorderBrush="Gray" BorderThickness="1" > <Ellipse x:Name="balR" Height="36" Width="36" Fill="Red" HorizontalAlignment="Left"> <Ellipse.RenderTransform> <TranslateTransform x:Name="ttR"/> </Ellipse.RenderTransform> </Ellipse> </Border> <Border BorderBrush="Gray" BorderThickness="1" Grid.Column="1"> <Ellipse x:Name="balG" Height="36" Width="36" Fill="Gray" HorizontalAlignment="Left"> <Ellipse.RenderTransform> <TranslateTransform x:Name="ttG"/> </Ellipse.RenderTransform> </Ellipse> </Border> <Border BorderBrush="Gray" BorderThickness="1" Grid.Column="1"> <Ellipse x:Name="balB" Height="36" Width="36" Fill="Blue" HorizontalAlignment="Left"> <Ellipse.RenderTransform> <TranslateTransform x:Name="ttB"/> </Ellipse.RenderTransform> </Ellipse> </Border> </StackPanel> <Button Content="go" Grid.Column="1" Grid.Row="1" Width="100" Height="40" FontSize="18"> <Button.Triggers> <EventTrigger RoutedEvent="Button.Click"> <BeginStoryboard> <Storyboard Duration="0:0:30"> <DoubleAnimation Duration="0:0:30" To="400" Storyboard.TargetName="ttR" Storyboard.TargetProperty="X"> </DoubleAnimation> <DoubleAnimationUsingKeyFrames Duration="0:0:30" Storyboard.TargetProperty="X" Storyboard.TargetName="ttG"> <SplineDoubleKeyFrame KeyTime="0:0:0.6" Value="400" KeySpline="1,0,0,1"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Duration="0:0:30" Storyboard.TargetProperty="X" Storyboard.TargetName="ttB"> <SplineDoubleKeyFrame KeyTime="0:0:0.6" Value="400" KeySpline="0,1,1,0"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Button.Triggers> </Button>