UWP Button添加圆角阴影(三)

时间:2022-09-07 11:48:33

原文:UWP Button添加圆角阴影(三)

Composition

DropShadow是CompositionAPI中的东西,使用Storyboard设置某个属性,就是频繁的触发put_xxx()方法,效率远远不如使用CompositionAnimation。

Composition对象的基类CompositionObject拥有一个属性叫ImplicitAnimations,可以通过他实现累死css的transition的效果,也就是对应属性修改的时候,平滑的过渡过去。

可以从DropShadowPanel的源代码中看到,DropShadow是设置在ShadowElement上的ChildVisual。

相关内容可以查阅将可视化层与 XAML 结合使用 - ElementCompositionPreview.SetElementChildVisual 方法

而我们要做的,是把整个构造过程倒过来,通过VisualTreeHelper,从DropShadow中拿到ShadowElement,然后获取他的ChildVisual和Shadow,将ImplicitAnimations设置到Shadow上。

下面贴代码:

public static class DropShadowPanelHelper
{
public static bool GetIsTransitionEnable(DropShadowPanel obj)
{
return (bool)obj.GetValue(IsTransitionEnableProperty);
} public static void SetIsTransitionEnable(DropShadowPanel obj, bool value)
{
obj.SetValue(IsTransitionEnableProperty, value);
} public static readonly DependencyProperty IsTransitionEnableProperty =
DependencyProperty.RegisterAttached("IsTransitionEnable", typeof(bool), typeof(DropShadowPanelHelper), new PropertyMetadata(false, IsTransitionEnablePropertyChanged)); private static void IsTransitionEnablePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != e.OldValue)
{
if (d is DropShadowPanel sender)
{
//尝试获取ShadowElement,如果为空,可能是DropShadowPanel还没有ApplyTemplate,注册DropShadowPanel的Loaded事件,在Loaded中再获取一次。
var shadowElement = sender.FindDescendantByName("ShadowElement") as Border;
if (shadowElement != null)
{
SetImplicitAnimation(shadowElement, (bool)e.NewValue);
}
else
{
sender.Loaded += DropShadowPanel_Loaded;
}
}
}
} private static void DropShadowPanel_Loaded(object sender, RoutedEventArgs e)
{
var dropShadowPanel = (DropShadowPanel)sender;
dropShadowPanel.Loaded -= DropShadowPanel_Loaded;
var shadowElement = dropShadowPanel.FindDescendantByName("ShadowElement") as Border;
if (shadowElement != null)
{
SetImplicitAnimation(shadowElement, GetIsTransitionEnable(dropShadowPanel));
}
} private static void SetImplicitAnimation(FrameworkElement element, bool IsEnable)
{
if (ElementCompositionPreview.GetElementChildVisual(element) is SpriteVisual shadowVisual &&
shadowVisual.Shadow is DropShadow shadow)
{
if (IsEnable)
{
//获取合成器
var compositor = shadowVisual.Compositor; //创建ImplicitAnimationCollection
var imp = compositor.CreateImplicitAnimationCollection(); //创建BlurRadius动画,注意不要忘记设置Duration和Target
var bluran = compositor.CreateScalarKeyFrameAnimation();
//插入一个表达式关键帧,帧在进度为1的时候,值是最终值
bluran.InsertExpressionKeyFrame(1f, "this.FinalValue");
bluran.Duration = TimeSpan.FromSeconds(0.2d);
bluran.Target = "BlurRadius"; //创建Offset动画
var offsetan = compositor.CreateVector3KeyFrameAnimation();
offsetan.InsertExpressionKeyFrame(1f, "this.FinalValue");
offsetan.Duration = TimeSpan.FromSeconds(0.2d);
offsetan.Target = "Offset"; //创建Opacity动画
var opacityan = compositor.CreateScalarKeyFrameAnimation();
opacityan.InsertExpressionKeyFrame(1f, "this.FinalValue");
opacityan.Duration = TimeSpan.FromSeconds(0.2d);
opacityan.Target = "Opacity"; //ImplicitAnimationCollection是IDictionary,每个子项都要是KeyFrame动画,子项的Key和动画的Target要一样。
ImplictAnimationCollection
imp[bluran.Target] = bluran;
imp[offsetan.Target] = offsetan;
imp[opacityan.Target] = opacityan; //给shadow设置ImplicitAnimations
shadow.ImplicitAnimations = imp;
}
else
{
var imp = shadow.ImplicitAnimations;
shadow.ImplicitAnimations = null;
if (imp != null)
{
imp.Dispose();
imp = null;
}
}
}
} }

表达式关键帧的关键字相关的内容可以查阅:ExpressionAnimation Class - Expression Keywords

最后的Xaml是这样的:

<Style TargetType="Button" x:Key="CornerRadiusShadowButtonStyle">
<Setter Property="Background" Value="#007acc" />
<Setter Property="Foreground" Value="White" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Padding" Value="20,10,20,10" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="True" />
<Setter Property="FocusVisualMargin" Value="-3" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="RootGrid">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="Shadow.OffsetY" Value="2" />
<Setter Target="Shadow.BlurRadius" Value="8" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="OffsetY" To="3" Duration="0" />
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="BlurRadius" To="12" Duration="0" />
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<control:DropShadowPanel x:Name="Shadow"
xmlns:control="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:helper="using:TestApp1.Helpers"
HorizontalContentAlignment="Stretch"
helper:DropShadowPanelHelper.IsTransitionEnable="True"
BlurRadius="5" OffsetX="1" OffsetY="1" Color="Black">
<Rectangle x:Name="Background" Fill="{TemplateBinding Background}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RadiusX="5" RadiusY="5" />
</control:DropShadowPanel>
<ContentPresenter x:Name="ContentPresenter"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTransitions="{TemplateBinding ContentTransitions}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

启用方式就是中的xmlns:helper="using:TestApp1.Helpers" helper:DropShadowPanelHelper.IsTransitionEnable="True"

VisualState中有两种写法,第一种是写在Setter中,优点是写的少,缺点是不能控制起始时间。

第二种是写在Storyboard中,Duration一定要是0,因为真正的动画我们定义在ImplicitAnimation中了,这里的Animation只是用来触发值修改,不需要插值。

最终效果有点小掉帧,是DropShadow的问题,17763中的ThemeShadow应该会有改善。。。

UWP Button添加圆角阴影(三)

UWP Button添加圆角阴影(三)的更多相关文章

  1. UWP Button添加圆角阴影(二)

    原文:UWP Button添加圆角阴影(二) 阴影 对于阴影呢,WindowsCommunityToolkit中已经有封装好的DropShadowPanel啦,只要引用Microsoft.Toolki ...

  2. UWP Button添加圆角阴影(一)

    原文:UWP Button添加圆角阴影(一) 众所周知,17763之前的UWP控件,大部分是没有圆角属性的:而阴影也只有17763中的ThemeShadow可以直接在xaml中使用,之前的版本只能用D ...

  3. 为input输入框添加圆角并去除阴影

    <input type="text" name="bianhao" value="" placeholder="请输入商品编 ...

  4. iOS 高效添加圆角效果实战讲解

    圆角(RounderCorner)是一种很常见的视图效果,相比于直角,它更加柔和优美,易于接受.但很多人并不清楚如何设置圆角的正确方式和原理.设置圆角会带来一定的性能损耗,如何提高性能是另一个需要重点 ...

  5. iOS开发-添加圆角效果高效实现

    圆角(RounderCorner)是一种很常见的视图效果,相比于直角,它更加柔和优美,易于接受.但很多人并不清楚如何设置圆角的正确方式和原理.设置圆角会带来一定的性能损耗,如何提高性能是另一个需要重点 ...

  6. &lbrace;django模型层&lpar;二&rpar;多表操作&rcub;一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询、分组查询、F查询和Q查询

    Django基础五之django模型层(二)多表操作 本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 xxx 七 ...

  7. CSS3圆角&comma;阴影&comma;透明

    CSS实现圆角,阴影,透明的方法很多,传统的方法都比较复杂,用CSS3就方便很多了,虽然现在各浏览器对CSS3的支持还不是很好,但不久的将来CSS3就会普及. 1.圆角 CSS3实现圆角有两种方法. ...

  8. HackTwelve 为背景添加圆角边框

    1.概要:     ShapeDrawable是一个为UI控件添加特效的好工具.这个技巧适用于那些可以添加背景的控件 2.添加圆角边框其实就是添加的背景那里不是直接添加图片,而是添加一个XML文件即可 ...

  9. (二)AS给button添加点击事件

    三种方法给Button添加点击事件 (一)通过button的id,添加继承View.OnClickListener的监听实现 <Button android:id="@+id/btn_ ...

随机推荐

  1. 挑子学习笔记:对数似然距离(Log-Likelihood Distance)

    转载请标明出处:http://www.cnblogs.com/tiaozistudy/p/log-likelihood_distance.html 本文是“挑子”在学习对数似然距离过程中的笔记摘录,文 ...

  2. Eclipse 打不开

    查看环境变量中是否存在重复的javahome变量路径 如上图存在-vm C:\ProgramData\Oracle\Java\javapath\javaw.exe,就和自己配置的javahome变量存 ...

  3. Oracle 记录插入时&OpenCurlyDoubleQuote;Invalid parameter binding ”错误

    出现这种错误的原因可能有一下几种: 由于OracleParameter[] parameters:中parameters的个数和对应的插入SQL语句中的冒号个数不等: 参数个数和冒号个数相等,但是如下 ...

  4. linux系统的常用命令

    linux系统中常用的命令如下(以后经常补充): cd ..   返回上一级 cd use  进入use目录

  5. Android SDK和N多Android开发资源

    开发资源 本文收集整理Android开发需要的Android SDK.工具.Android开发教程.Android设计规范,免费的设计素材等. 欢迎大家推荐自己在Android开发过程中用的好用的工具 ...

  6. 利用Visual GDB在Visual Studio中进行Android开发

    转载请注明http://www.cnblogs.com/adong7639/p/4119467.html 无意中发现了Visual GDB这个工具,可以再Visual Studio中进行Android ...

  7. discuz插件开发新手入门 超详细

    作为一个新手,目前也是刚刚玩转discuz的插件功能,好东西不敢独享,就拿出来大家一起分享入门的过程.现在网上很多关于discuz的插件教程都是很简单的教程,原因可能是这个东西是商业化的东西,本着分享 ...

  8. Golden32 别名时中文 报ORA-00911&colon; invalid character错误

    查询数据库软件我一般用两个:PL SQL和golden32:使用golden32-之前使用的时候别名为中文是没有任何问题:直到我想将PL SQL汉化(使用中文包chinese.exe),汉化完后再次查 ...

  9. 学一点 mysql 双机异地热备份----快速理解mysql主从,主主备份原理及实践

    双机热备的概念简单说一下,就是要保持两个数据库的状态 自动同步.对任何一个数据库的操作都自动应用到另外一个数据库,始终保持两个数据库数据一致. 这样做的好处多. 1. 可以做灾备,其中一个坏了可以切换 ...

  10. POJ3436 ACM Computer Factory 【最大流】

    ACM Computer Factory Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5412   Accepted: 1 ...