UWP Button添加圆角阴影(二)

原文: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>

原文地址:https://www.cnblogs.com/blue-fire/p/9768760.html

时间: 2024-08-23 22:30:45

UWP Button添加圆角阴影(二)的相关文章

UWP Button添加圆角阴影(三)

原文:UWP Button添加圆角阴影(三) Composition DropShadow是CompositionAPI中的东西,使用Storyboard设置某个属性,就是频繁的触发put_xxx()方法,效率远远不如使用CompositionAnimation. Composition对象的基类CompositionObject拥有一个属性叫ImplicitAnimations,可以通过他实现累死css的transition的效果,也就是对应属性修改的时候,平滑的过渡过去. 可以从DropSh

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

<input type="text" name="bianhao" value="" placeholder="请输入商品编号" maxlength="10" size="10" style="width:105px; margin:0px 0px 0px 12px;height:22px;border-radius:4px; border:1px solid #DBDB

为Input输入框添加圆角并去除阴影 去除获得焦点时方角样式

目录 1.为Input输入框添加圆角并去除阴影 2.去除获得焦点时方角样式 内容 1.为Input输入框添加圆角并去除阴影 1.1 border-radius不同浏览器下兼容设置: .boder-radius{ -webkit-border-radius:6px;//适配以webkit为核心的浏览器(chrome.safari等) -moz-border-radius:6px;//适配firefox浏览器 -ms-border-radius:6px;//适配IE浏览器 -o-border-rad

WPF之路二 button添加背景图片点击后图片闪烁问题

在为button添加背景图片的时候,点击后发现图片闪烁,我们仔细观察,其实Button不仅仅只是在点击后会闪烁,在其通过点击或按Tab键获得焦点后都会闪烁,而通过点击其他按钮或通过按Tab键让Button失去焦点后就不闪烁了.如此我们可以推测出这不是点击或其他什么的问题而是焦点的问题,那么我们只要设置Button的Focusable属性为False就行了. 网上给的答案是要在button属性设置Focusable="False" ,无奈找属性栏里没有找到Focusable,于是在代码里

CSS3圆角,阴影,透明

CSS实现圆角,阴影,透明的方法很多,传统的方法都比较复杂,用CSS3就方便很多了,虽然现在各浏览器对CSS3的支持还不是很好,但不久的将来CSS3就会普及. 1.圆角 CSS3实现圆角有两种方法. 第一种是背景图像,传统的CSS每个元素只能有一个背景图像,但是CSS3可以允许一个元素有多个背景图像.这样给一个元素添加4个1/4圆的背景图像,分别位于4个角上就可以实现圆角了. Html代码   .box { /* 首先定义要使用的4幅图像为背景图 */ background-image: url

MFC 基础知识:对话框背景添加图片和按钮Button添加图片

很长时间没有接触MFC相关的知识了,我大概是在大二时候学习的MFC相关知识及图像处理,现在由于要帮个朋友完成个基于C++的程序,所以又回顾了下相关知识.的确,任何知识一段时间过后都比较容易忘记,但回顾起来还是很有印象的. 这篇文章主要是回顾以前的MFC基础知识,给对话框添加背景图片和给按钮button添加背景图片:希望此篇基础性文章对大家有所帮助!同时为下次做MFC相关知识提供点此时所想所感吧.内容比较简单,高手飘过~ 一. 对话框背景添加图片 首先通过VS2012创建MFC对话框应用程序,项目

IOS UIView圆角,阴影,边框,渐增光泽

圆角 sampleView.layer.cornerRadius = 2.5; // 圓角的弧度sampleView.layer.masksToBounds = YES; 阴影 sampleView.layer.shadowColor = [[UIColor blackColor] CGColor];sampleView.layer.shadowOffset = CGSizeMake(3.0f, 3.0f); // [水平偏移, 垂直偏移]sampleView.layer.shadowOpaci

Qt之圆角阴影边框

Qt的主窗体要做出类似WIN7那种圆角阴影边框,这一直是美工的需求. 这里是有一些门道的,尤其是,这里藏着一个很大的秘密. 这个秘密是一个QT的至少横跨3个版本,存在了2年多的BUG... https://bugreports.qt-project.org/browse/QTBUG-17548 ok,看完这个BUG的应急解决办法,然后你再需加上如下代码例子,就可见效了 void MainWindow::paintEvent(QPaintEvent *event){    QPainterPath

给button添加长按手势并侦测到此button

1, 添加手势 self.longPressRecognizer = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(handleLongPress:)];[btn addGestureRecognizer:self.longPressRecognizer]; 2,得到当前执行长点选的button - (void)handleLongPress:(UILongPressGestureRecogni