UWP Button添加圆角阴影(二)
阴影
对于阴影呢,WindowsCommunityToolkit中已经有封装好的DropShadowPanel啦,只要引用Microsoft.Toolkit.Uwp.UI.Controls这个Nuget包就可以使用啦。
直接把阴影套在咱们的圆角Button外面呢,会出现圆角的Button映出直角的阴影的丑陋状况。对于这种情况肯定是有处理方式的。
看DropShadowPanel的源码,对Content的特殊类型做了处理。下面我详细的说下。
CompositionAPI中的DropShadow这个东西,非常反人类的两点:
- 只有SpriteVisual拥有Shadow熟悉,也就是说你不能直接给Xaml元素的Visual附加阴影;
- 给SpriteVisual设置阴影后,这个阴影是绘制在SpriteVisual上面的。
所以呢,你去看DropShadowPanel的源码,是ContentPresenter后面附了个什么东西当SpriteVisual的Host,然后在Host的ChildVisual也就是SpriteVisual上面设置阴影。也就是说,这个阴影,和Content是没毛关系的。
那么,官方Demo中Image、Shape、TextBlock的阴影是怎么做到的呢?这就要提到他们三个拥有的一个方法了。说实话,这是我第一次见到多个控件拥有相同的方法,却没有继承相同的接口的情况。。。方法名叫GetAlphaMask(),可以返回一个CompositionSurfaceBrush,Brush的内容是控件的内容填黑,其他地方留空,给DropShadow.Mask设置成这个Brush,阴影就会按照这个轮廓去绘制。
破案之后呢,思路就(救)出来了,按照这个方法,我们只要给DropShadowPanel的Content设置一个Rectangle,就能获得圆角的阴影啦。
既然上面已经有一个Rectangle当背景,这里就再利用一下,给背景外面套个DropShadowPanel,接下来结构变成了这样子。
<Style TargetType="Button" x:Key="CornerRadiusShadowButtonStyle">
<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">
<Storyboard>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<control:DropShadowPanel x:Name="Shadow" xmlns:control="using:Microsoft.Toolkit.Uwp.UI.Controls">
<Rectangle x:Name="Background"></Rectangle>
</control:DropShadowPanel>
<ContentPresenter x:Name="ContentPresenter">
</ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
注意这里有个小坑,DropShadowPanel的HorizontalContentAlignment默认是Left,Content里如果只装Rectangle,是撑不开的。。。要做如下设置:
<control:DropShadowPanel x:Name="Shadow" xmlns:control="using:Microsoft.Toolkit.Uwp.UI.Controls" HorizontalContentAlignment="Stretch">
<Rectangle x:Name="Background" Fill="{TemplateBinding Background}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RadiusX="5" RadiusY="5" />
</control:DropShadowPanel>
接下来就是编写VisualState了,如果要对DropShadowPanel进行有过渡的动画,需要在DoubleAnimation中设置EnableDependentAnimation="True",不然只播放起始和终止状态。详情请见:情节提要动画 - 从属动画和独立动画。
注:调试过程中热更新DropShadowPanel的BlurRadius和Offset动画,再播放会掉帧,重新运行一下就好了。

但是用DoubleAnimation去控制CompositionAPI中的动画是很不好的,Composition有自己的Animation系统,我们将会在下一篇文章中一起给DropShadowPanel附加隐式(过渡)动画。
下面是完整的代码:
<Style TargetType="Button" x:Key="CornerRadiusShadowButtonStyle">
<Setter Property="Background" Value="{ThemeResource ButtonBackground}" />
<Setter Property="Foreground" Value="{ThemeResource ButtonForeground}" />
<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">
<VisualStateGroup.Transitions>
<VisualTransition To="Normal" >
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="OffsetY" To="1" Duration="0:0:0.1" EnableDependentAnimation="True" />
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="BlurRadius" To="5" Duration="0:0:0.1" EnableDependentAnimation="True" />
</Storyboard>
</VisualTransition>
<VisualTransition To="PointerOver" >
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="OffsetY" To="2" Duration="0:0:0.1" EnableDependentAnimation="True" />
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="BlurRadius" To="8" Duration="0:0:0.1" EnableDependentAnimation="True" />
</Storyboard>
</VisualTransition>
<VisualTransition To="Pressed" >
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="OffsetY" To="3" Duration="0:0:0.1" EnableDependentAnimation="True" />
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="BlurRadius" To="12" Duration="0:0:0.1" EnableDependentAnimation="True" />
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" >
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="OffsetY" To="1" Duration="0" EnableDependentAnimation="True" />
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="BlurRadius" To="5" Duration="0" EnableDependentAnimation="True" />
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="OffsetY" To="2" Duration="0" EnableDependentAnimation="True" />
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="BlurRadius" To="8" Duration="0" EnableDependentAnimation="True" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="OffsetY" To="3" Duration="0" EnableDependentAnimation="True" />
<DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="BlurRadius" To="12" Duration="0" EnableDependentAnimation="True" />
</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" HorizontalContentAlignment="Stretch"
BlurRadius="5" ShadowOpacity="0.8" 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>
UWP Button添加圆角阴影(二)的更多相关文章
- UWP Button添加圆角阴影(三)
原文:UWP Button添加圆角阴影(三) Composition DropShadow是CompositionAPI中的东西,使用Storyboard设置某个属性,就是频繁的触发put_xxx() ...
- UWP Button添加圆角阴影(一)
原文:UWP Button添加圆角阴影(一) 众所周知,17763之前的UWP控件,大部分是没有圆角属性的:而阴影也只有17763中的ThemeShadow可以直接在xaml中使用,之前的版本只能用D ...
- 为input输入框添加圆角并去除阴影
<input type="text" name="bianhao" value="" placeholder="请输入商品编 ...
- (二)AS给button添加点击事件
三种方法给Button添加点击事件 (一)通过button的id,添加继承View.OnClickListener的监听实现 <Button android:id="@+id/btn_ ...
- WPF之路二: button添加背景图片点击后图片闪烁问题
在为button添加背景图片的时候,点击后发现图片闪烁,我们仔细观察,其实Button不仅仅只是在点击后会闪烁,在其通过点击或按Tab键获得焦点后都会闪烁,而通过点击其他按钮或通过按Tab键让Butt ...
- [Xcode 实际操作]二、视图与手势-(5)给图像视图添加圆角效果
目录:[Swift]Xcode实际操作 本文将演示给矩形图片添加圆角效果 import UIKit class ViewController: UIViewController { override ...
- Cocos Creator 为Button添加事件的两种方法
Button添加事件 Button 目前只支持 Click 事件,即当用户点击并释放 Button 时才会触发相应的回调函数.通过脚本代码添加回调方法一这种方法添加的事件回调和使用编辑器添加的事件回调 ...
- CSS3圆角,阴影,透明
CSS实现圆角,阴影,透明的方法很多,传统的方法都比较复杂,用CSS3就方便很多了,虽然现在各浏览器对CSS3的支持还不是很好,但不久的将来CSS3就会普及. 1.圆角 CSS3实现圆角有两种方法. ...
- HackTwelve 为背景添加圆角边框
1.概要: ShapeDrawable是一个为UI控件添加特效的好工具.这个技巧适用于那些可以添加背景的控件 2.添加圆角边框其实就是添加的背景那里不是直接添加图片,而是添加一个XML文件即可 ...
随机推荐
- Partition Array Into Three Parts With Equal Sum LT1013
Given an array A of integers, return true if and only if we can partition the array into three non-e ...
- 字符串匹配 - sunday算法
常见的字符串匹配算法有BF.KMP(教科书中非常经典的).BM.Sunday算法 这里主要想介绍下性能比较好并且实现比较简单的Sunday算法 . 基本原理: 从前往后匹配,如果遇到不匹配情况判断母串 ...
- nginx的hash
hash结构中有若干个桶,桶内是hash(key)值相同的若干数据. 查找数据时,首先对key值进行hash计算,然后hash值对桶的个数进行求余,得到数据所在的桶.然后在桶中使用key逐个查找,直到 ...
- JS高级-String- RegExp- Math- Date:
1. String: 切割: 将一个字符串,按指定分隔符,切割为多段子字符串 简单切割: 切割符是固定的 var arr=str.split("切割符") 强调: 切割后的结果中, ...
- 一波水题 MZOJ 1035: 贝克汉姆
#include <bits/stdc++.h> using namespace std; ; int n,m; int v[N],w[N],f[N]; int main() { scan ...
- etf基金和lof基金区别
①,含义不同.etf即交易指数开放基金,是跟踪某一指数的可以在交易所上市的开放式基金.lof基金是上市向开放基金,是中国首创的一种基金类型,也是etf基金的中国化.②,申购赎回的场所不同.etf和lo ...
- java启动jar包中的指定类
运行jar文件的方法是:java -jar xxx.jar 希望运行里面的具体某个类,这时可以通过:java -cp xxx.jar xxx.com.xxxx 其中-cp命令是将xxx.jar加入到c ...
- 详细解读 :java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed,Java报错之Connection is read-only.
问题分析: 实际开发项目中,进行insert的时候,产生这个问题是Spring框架的一个安全权限保护方法,对于方法调用的事物保护,一般配置如下: <!-- 事务管理 属性 --> < ...
- JDK 1.5、1.6 & 中文版API,J2EE5API大全(借鉴)
个人分类: Java文档 Sun 公司提供的Java API Docs是学习和使用Java语言中最经常使用的参考资料之一.但是长期以来此文档只有英文版,对于中国地区的Java开发者 ...
- oracle学习笔记一:用户管理(3)用户口令管理
当某个用户不断的尝试密码进行登录数据库是很危险的,因此对密码(口令)的管理十分重要.好在我们可以限制登录次数,超过某些次数的登录将会把用户锁住,隔一段时间才允许其登录,这和你的手机是不是有点一样,你的 ...