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

众所周知,17763之前的UWP控件,大部分是没有圆角属性的;而阴影也只有17763中的ThemeShadow可以直接在xaml中使用,之前的版本只能用DropShadow,用法极其别扭。

本文就给出一个虽然很别扭,但是效果还不错的,比较通用的圆角+阴影的方案。

概念

我们先思考一下,用户感知到的圆角按钮,到底是个什么东西。

任何一个按钮,不外乎Background和Content两部分,用户可以从Content中获取到按钮的信息,而按钮的形状,在没有Border的情况下,用户对Button形状最直观的感受就是Background!

也就是说,我们只要让一个按钮的Background是一个圆角矩形,他在大多数情况下,就是一个圆角按钮!

按照这个思路,我们可以在17763之前的UWP,也就是大多数控件都没有CornerRadius这个属性的环境里,造出许多圆角的控件。

圆角

从Generic.xaml中,把Button的Style复制出一份,删除没有必要的东西,就成了下面的样子:

  1. <Style TargetType="Button">
  2. <Setter Property="Background" Value="{ThemeResource ButtonBackground}" />
  3. <Setter Property="Foreground" Value="{ThemeResource ButtonForeground}" />
  4. <Setter Property="BorderBrush" Value="{ThemeResource ButtonBorderBrush}" />
  5. <Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
  6. <Setter Property="Padding" Value="8,4,8,4" />
  7. <Setter Property="HorizontalAlignment" Value="Left" />
  8. <Setter Property="VerticalAlignment" Value="Center" />
  9. <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
  10. <Setter Property="FontWeight" Value="Normal" />
  11. <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
  12. <Setter Property="UseSystemFocusVisuals" Value="True" />
  13. <Setter Property="FocusVisualMargin" Value="-3" />
  14. <Setter Property="Template">
  15. <Setter.Value>
  16. <ControlTemplate TargetType="Button">
  17. <Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
  18. <VisualStateManager.VisualStateGroups>
  19. <VisualStateGroup x:Name="CommonStates">
  20. <VisualState x:Name="Normal" />
  21. <VisualState x:Name="PointerOver">
  22. <Storyboard>
  23. <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
  24. <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPointerOver}" />
  25. </ObjectAnimationUsingKeyFrames>
  26. <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
  27. <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPointerOver}" />
  28. </ObjectAnimationUsingKeyFrames>
  29. <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
  30. <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPointerOver}" />
  31. </ObjectAnimationUsingKeyFrames>
  32. </Storyboard>
  33. </VisualState>
  34. <VisualState x:Name="Pressed">
  35. <Storyboard>
  36. <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
  37. <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPressed}" />
  38. </ObjectAnimationUsingKeyFrames>
  39. <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
  40. <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPressed}" />
  41. </ObjectAnimationUsingKeyFrames>
  42. <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
  43. <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPressed}" />
  44. </ObjectAnimationUsingKeyFrames>
  45. </Storyboard>
  46. </VisualState>
  47. <VisualState x:Name="Disabled">
  48. <Storyboard>
  49. <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
  50. <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundDisabled}" />
  51. </ObjectAnimationUsingKeyFrames>
  52. <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
  53. <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushDisabled}" />
  54. </ObjectAnimationUsingKeyFrames>
  55. <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
  56. <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundDisabled}" />
  57. </ObjectAnimationUsingKeyFrames>
  58. </Storyboard>
  59. </VisualState>
  60. </VisualStateGroup>
  61. </VisualStateManager.VisualStateGroups>
  62. <ContentPresenter x:Name="ContentPresenter"
  63. BorderBrush="{TemplateBinding BorderBrush}"
  64. BorderThickness="{TemplateBinding BorderThickness}"
  65. Content="{TemplateBinding Content}"
  66. ContentTransitions="{TemplateBinding ContentTransitions}"
  67. ContentTemplate="{TemplateBinding ContentTemplate}"
  68. Padding="{TemplateBinding Padding}"
  69. HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
  70. VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
  71. AutomationProperties.AccessibilityView="Raw" />
  72. </Grid>
  73. </ControlTemplate>
  74. </Setter.Value>
  75. </Setter>
  76. </Style>

其实大部分内容不重要,我们先来分析一下这个结构,删掉所有布局之外的属性,就剩下很单纯的Grid装着一个ContentPresenter,是这样的:

  1. <Style TargetType="Button" x:Key="CornerRadiusShadowButtonStyle">
  2. <Setter Property="Template">
  3. <Setter.Value>
  4. <ControlTemplate TargetType="Button">
  5. <Grid x:Name="RootGrid">
  6. <VisualStateManager.VisualStateGroups>
  7. <VisualStateGroup x:Name="CommonStates">
  8. <VisualState x:Name="Normal" />
  9. <VisualState x:Name="PointerOver"/>
  10. <VisualState x:Name="Pressed"/>
  11. <VisualState x:Name="Disabled"/>
  12. </VisualStateGroup>
  13. </VisualStateManager.VisualStateGroups>
  14. <ContentPresenter x:Name="ContentPresenter"/>
  15. </Grid>
  16. </ControlTemplate>
  17. </Setter.Value>
  18. </Setter>
  19. </Style>

圆角的属性呢,只有在Border,Rectangle中有,当然你要是足够闲,也可以撸Path...

结果很明显了对吧,这就是圆角的两个实现方式,ContentPresenter外面套Border,或者后面放Rectangle当Background。

Border的方式呢,优缺点都很明显。

优点是Border的CornerRadius可以分别设置四个角的半径,而且可以设置给Button设置Border相关属性的时候,让Border的相关属性按照我们定义的Border的形状去绘制。

缺点呢,就是在PC端,Border设置CornerRadius后,会Clip掉内容超出Border的部分(由于17763之前的UWP没有GeometryClip,所以这个圆角Clip也算是个特性...),其实我们可以利用这个特性做圆形头像,圆形播放器啥的...

而Rectangle呢,虽然不能分别设置四个角的半径,但是可以分别设置X的半径和Y的半径...说起来感觉好诡异...

出个人喜好,还有我不喜欢画Border的风格,就选Rectangle的解决方案了。修改完成之后的Style结构应该是这个模样的:

  1. <Style TargetType="Button" x:Key="CornerRadiusShadowButtonStyle">
  2. <Setter Property="Template">
  3. <Setter.Value>
  4. <ControlTemplate TargetType="Button">
  5. <Grid x:Name="RootGrid">
  6. <VisualStateManager.VisualStateGroups>
  7. <VisualStateGroup x:Name="CommonStates">
  8. <VisualState x:Name="Normal" />
  9. <VisualState x:Name="PointerOver"/>
  10. <VisualState x:Name="Pressed"/>
  11. <VisualState x:Name="Disabled"/>
  12. </VisualStateGroup>
  13. </VisualStateManager.VisualStateGroups>
  14. <Rectangle x:Name="Background" />
  15. <ContentPresenter x:Name="ContentPresenter"/>
  16. </Grid>
  17. </ControlTemplate>
  18. </Setter.Value>
  19. </Setter>
  20. </Style>

注意事项:VisualStateManager必须放到控件根元素内,比如Page的VisualStateManager就必须放到Page内第一个元素比如Grid或者StackPanel里,不然是不会生效的。

完整版是这样的,有改颜色的需求可以撸一下VisualState里的颜色:

  1. <Style TargetType="Button" x:Key="CornerRadiusShadowButtonStyle">
  2. <Setter Property="Background" Value="{ThemeResource ButtonBackground}"/>
  3. <Setter Property="Foreground" Value="{ThemeResource ButtonForeground}"/>
  4. <Setter Property="BorderBrush" Value="Transparent" />
  5. <Setter Property="BorderThickness" Value="0" />
  6. <Setter Property="Padding" Value="20,10,20,10" />
  7. <Setter Property="HorizontalAlignment" Value="Left" />
  8. <Setter Property="VerticalAlignment" Value="Center" />
  9. <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
  10. <Setter Property="FontWeight" Value="Normal" />
  11. <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
  12. <Setter Property="UseSystemFocusVisuals" Value="True" />
  13. <Setter Property="FocusVisualMargin" Value="-3" />
  14. <Setter Property="Template">
  15. <Setter.Value>
  16. <ControlTemplate TargetType="Button">
  17. <Grid x:Name="RootGrid">
  18. <VisualStateManager.VisualStateGroups>
  19. <VisualStateGroup x:Name="CommonStates">
  20. <VisualState x:Name="Normal" />
  21. <VisualState x:Name="PointerOver">
  22. <Storyboard>
  23. <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill">
  24. <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPointerOver}" />
  25. </ObjectAnimationUsingKeyFrames>
  26. </Storyboard>
  27. </VisualState>
  28. <VisualState x:Name="Pressed">
  29. <Storyboard>
  30. <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill">
  31. <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPressed}" />
  32. </ObjectAnimationUsingKeyFrames>
  33. </Storyboard>
  34. </VisualState>
  35. <VisualState x:Name="Disabled">
  36. <Storyboard>
  37. <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill">
  38. <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundDisabled}" />
  39. </ObjectAnimationUsingKeyFrames>
  40. </Storyboard>
  41. </VisualState>
  42. </VisualStateGroup>
  43. </VisualStateManager.VisualStateGroups>
  44. <Rectangle x:Name="Background" Fill="{TemplateBinding Background}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RadiusX="5" RadiusY="5" />
  45. <ContentPresenter x:Name="ContentPresenter"
  46. BorderBrush="{TemplateBinding BorderBrush}"
  47. BorderThickness="{TemplateBinding BorderThickness}"
  48. Content="{TemplateBinding Content}"
  49. ContentTransitions="{TemplateBinding ContentTransitions}"
  50. ContentTemplate="{TemplateBinding ContentTemplate}"
  51. Padding="{TemplateBinding Padding}"
  52. HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
  53. VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
  54. AutomationProperties.AccessibilityView="Raw" />
  55. </Grid>
  56. </ControlTemplate>
  57. </Setter.Value>
  58. </Setter>
  59. </Style>

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

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

    原文:UWP Button添加圆角阴影(三) Composition DropShadow是CompositionAPI中的东西,使用Storyboard设置某个属性,就是频繁的触发put_xxx() ...

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

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

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

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

  4. CSS3圆角,阴影,透明

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

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

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

  6. iOS给UIimage添加圆角的两种方式

    众所周知,给图片添加圆角有CALayer的cornerRadius, 比如: 最直接的方法: imgView.layer.cornerRadius1=110;   imgView.clipsToBou ...

  7. iOS 在xib或storyboard里为控件添加圆角、外框和外框颜色

    如果要在xib和storyboard里为控件添加圆角和外框宽度,只要这样做就可以 layer.borderWidth     设置外框宽度属性 layer.cornerRadius    设置圆角属性 ...

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

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

  9. iOS在xib或storyboard里为控件添加圆角、外框和外框颜色

    如果要在xib和storyboard里为控件添加圆角和外框宽度,只要这样做就可以: layer.borderWidth 设置外框宽度属性 layer.cornerRadius 设置圆角属性 只要为属性 ...

随机推荐

  1. Chrome firefox ie等浏览器空格(&nbsp;)兼容问题

    使用(&nbsp:)空格浏览器之间,显示的不一样,对不起等现象. 解决方案: 用半角空格&ensp:或者全角空格&emsp:就可以了,&ensp:相当于半格中文字符的宽 ...

  2. OneZero第三周第一次站立会议(2016.4.4)

    1. 时间: 13:30--13:45  共计15分钟. 2. 成员: X 夏一鸣 * 组长 (博客:http://www.cnblogs.com/xiaym896/), G 郭又铭 (博客:http ...

  3. Python学习杂记

    Python中关键字yield有什么作用? 首先得理解generators,而理解generators前还要理解iterables: 你可以用在for...in...语句中的都是可迭代的:比如list ...

  4. 非关系型数据库MongoDB

    爆炸式发展的NoSQL技术 在过去的很长一段时间中,关系型数据库(Relational Database Management System)一直是最主流的数据库解决方案,他运用真实世界中事物与关系来 ...

  5. linux 安装 ORACLE JDK 8

    1.卸载默认的OPENJDK 查看 open jdk 的安装 rpm -qa | grep java 卸载 openjdk rpm -e --nodeps java-1.7.0-openjdk-1.7 ...

  6. vue的computed属性

    vue的computed属性要注意的两个地方,1,必须有return,2,使用属性不用括号 <div> <input type="text" v-model=&q ...

  7. ACM-ICPC 2018 徐州赛区网络预赛 B BE, GE or NE(博弈,记忆化搜索)

    链接https://nanti.jisuanke.com/t/31454 思路 开始没读懂题,也没注意看数据范围(1000*200的状态,记忆化搜索随便搞) 用记忆化搜索处理出来每个状态的胜负情况 因 ...

  8. 解决python代码中含有中文报错

    python中写入中文时报错如下图所示: 依照网上解决方法:在py文件中加入:#encoding=utf-8 然后继续报错如下图所示: 解决方法: 在py文件中加入: import sysreload ...

  9. w7 目录

    第17章 期中架构体系介绍 期中架构环境准备 01-期中架构内容简介 02-期中架构大酒楼详解 03-期中架构使用到的软件简介 04-期中架构运维角度观察与使用的软件 05-重头开始创建一台新的虚拟机 ...

  10. POJ 2433 Landscaping (贪心)

    题意:给定一个序列表示一群山,要你保留最多 K 个山峰,最少要削去多少体积和土.一个山峰是指一段连续的相等的区间,并且左边和右边只能比这个区间低,或者是边界. 析:贪心,每次都寻找体积最小的山峰,然后 ...