Loading

WPF Animation For SizeChanged Of UIElement

效果图

学到一个新词:

Show me the money

shadow radius12

背景

这几天查资料,看到 CodeProject 上面的一篇 Post 《Advanced Custom TreeView Layout in WPF》,感谢作者,将 TreeView 重定义了布局,效果如上图所示,区别在于,没有展开和收拢的动画。正巧当下在浏览一些 Behavior 的内容,突发奇想写了一个 SizeChangedAnimationBehavior,可用来附加到大多数 FrameworkElement 上,实现如上的对 SizeChanged 应用动画的效果。

考虑使用一个通用的 SizeChangedAnimationBehavior 来实现对 FrameworkElement 的功能附加,好处是功能可热插拔,可通用等。

一、代码

private void AssociatedObjectOnSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)
{
	// NewSize 属性,如果存在 double.NaN,则处于一次动画中,跳过此次 OnSizeChanged 处理
	if (double.NaN.Equals(GetNewSize(AssociatedObject).Width) || double.NaN.Equals(GetNewSize(AssociatedObject).Height)) return;

	Size oldSize = GetOldSize(AssociatedObject);

	// 产生动画,注意,这里需要使用 ActualWidth/ActualHeight,并需要使用 FillBehavior.HoldEnd。这里的 Duration 可以扩展为一个附加属性,提高灵活性
	DoubleAnimation wAnimation = new DoubleAnimation(oldSize.Width, AssociatedObject.ActualWidth, new Duration(TimeSpan.FromMilliseconds(150)), FillBehavior.HoldEnd);
	DoubleAnimation hAnimation = new DoubleAnimation(oldSize.Height, AssociatedObject.ActualHeight, new Duration(TimeSpan.FromMilliseconds(150)), FillBehavior.HoldEnd);

	// 动画结束时,需要解除属性的动画锁定,即调用 AssociatedObject.BeginAnimation(FrameworkElement.WidthProperty, null);
	// 然后设置 NewSize 对应动画属性为 0(非 NaN),保证下次动画顺利执行
	wAnimation.Completed += (o, args) =>
	{
		AssociatedObject.BeginAnimation(FrameworkElement.WidthProperty, null);
		double height = GetNewSize(AssociatedObject).Height;
		SetNewSize(AssociatedObject, new Size(0, height));
	};
	hAnimation.Completed += (o, args) =>
	{
		AssociatedObject.BeginAnimation(FrameworkElement.HeightProperty, null);
		double width = GetNewSize(AssociatedObject).Width;
		SetNewSize(AssociatedObject, new Size(width, 0));
	};

	// 设置 OldSize 为 ActualSize,为下次动画做准备
	SetOldSize(AssociatedObject, new Size(AssociatedObject.ActualWidth, AssociatedObject.ActualHeight));

	// 设置 NewSize 为 NaN,表明当前无 NewSize,处于动画执行中,执行结束后,NewSize 将恢复为 0
	SetNewSize(AssociatedObject, new Size(double.NaN, double.NaN));

	// 执行动画
	AssociatedObject.BeginAnimation(FrameworkElement.WidthProperty, wAnimation);
	AssociatedObject.BeginAnimation(FrameworkElement.HeightProperty, hAnimation);
}

代码比较简单,注意注释说明。

其中,OldSize/NewSize 是两个附加属性。

调用如下:

<TextBox x:Name="TxtAnimated" VerticalAlignment="Top" Width="200" TextWrapping="Wrap" Margin="213,12,0,-27" HorizontalAlignment="Left" Grid.Row="2">
	<i:Interaction.Behaviors>
		<behaviors:SizeChangedAnimationBehavior/>
	</i:Interaction.Behaviors>
</TextBox>

二、其他应用效果

1)如下图,Button 的 Resize 操作,可实现动画效果;

2)如下图,Textbox 等实现 Height 的动画效果。此效果灵感(测试UI)来源于 《WPF TextBox with Animated Overflow》,感谢作者。

shadow radius12

三、Behavior

关于 Behavior,这里不细说,大佬们的博客太多。本文主要学习于周银辉大佬的 《从WPF的AttachProperty到Sliverlight3中的Behavior》,感谢作者,很棒的文章。

posted @ 2018-07-20 23:08  NLNet  阅读(90)  评论(0编辑  收藏  举报