1. 什么是长阴影

前几年扁平化设计(Flat Design)十分流行,后来在扁平化的基础上又流行起了长阴影(Long Shadow)。长阴影其实就是扩展了对象的投影,感觉是一种光线照射下的影子,通常采用角度为 45 度的投影,给对象添加了一份立体感。长阴影快速发展为流行的设计趋势,并经常被应用到扁平设计方案的对象。它很适合用在较小的元素上,一时之间几乎应用的图标都加上了长阴影。(不过现在又不流行了)

2. 使用GetAlphaMask和ContainerVisual制作长阴影

要在UWP中制作长阴影的话,可以用GetAlphaMask拿到轮廓,做成灰色,然后复制一百几十个摆在后面。不过当然并不是直接创建这么多个UIElement,而是使用ContainerVisual类实现这个功能。ContainerVisual用于组合子级的Visual,只需简单地调用VisualCollection.InsertAtBottom即可。

下面是具体的实现例子,和上篇文章介绍的一样,首先在需要阴影的元素(TitleElement)后面放一个用于显示阴影的UIElement(ShadowElement),布局如下:

<Grid Background="#FFE87A69" Padding="40" Margin="50" x:Name="ShadowRoot">
<Rectangle x:Name="ShadowElement" />
<TextBlock Text="One Pomodoro" Foreground="#FFfee8da" FontSize="64" x:Name="TitleElement"/>
</Grid>

然后在代码里创建一个ContainerVisual并使用ElementCompositionPreview.SetElementChildVisual将这个ContainerVisual设置到ShadowElement的可视化层:

var textVisual = ElementCompositionPreview.GetElementVisual(TitleElement);
compositor = textVisual.Compositor;
containerVisual = compositor.CreateContainerVisual();
ElementCompositionPreview.SetElementChildVisual(ShadowElement, containerVisual);

之后调用TitleElement的GetAlphaMask获取轮廓,然后将这个轮廓作为Mask设置到CompositionMaskBrush的Mask属性,重复一百次:

var mask = TitleElement.GetAlphaMask();

var shadowColor = Color.FromArgb(255, 160, 59, 49);
int depth = 100;
for (int i = 0; i < depth; i++)
{
//创建Brush
var maskBrush = compositor.CreateMaskBrush();
maskBrush.Mask = mask;
maskBrush.Source = compositor.CreateColorBrush(shadowColor); //创建Visual
var visual = compositor.CreateSpriteVisual();
visual.Brush = maskBrush;
visual.Offset = new Vector3(i + 1, i + 1, 0); //将Visual添加到ContainerVisual
containerVisual.Children.InsertAtBottom(visual); //同步Visual和TextVisual的尺寸
var bindSizeAnimation = compositor.CreateExpressionAnimation("textVisual.Size");
bindSizeAnimation.SetReferenceParameter("textVisual", textVisual);
visual.StartAnimation("Size", bindSizeAnimation);
}

然后终于……

……还是没完成,还需要为ContainerVisual设置Clip以免阴影越界。看起来需要写很多代码去实现,但其实有个简单的方法,将外面那层的ShadowRoot的CornerRadius设置为1,Grid就会自动自觉把超出范围的内容裁剪掉。虽然不知道具体原理,但有需要的话其它情况也可以偷懒这样做,也许有人不喜欢圆角,但区区1像素的圆角你不说我不说又有谁会知道呢。

Grid Background="#FFE87A69" Padding="40" Margin="50" x:Name="ShadowRoot" CornerRadius="1">

这样一个漂亮的长阴影就完成了。

3. 淡出的阴影

要实现淡出的阴影原理也很简单,别想太复杂,就只是准备好多个颜色渐渐改变的Visual,插进去ContainerVisual里就完成了。代码及效果如下(顺便一提这种情况下Vector3真好用):

int depth = 60;
float opacity = 0.3f;
Vector3 background = new Vector3(232, 122, 105); var maskBrush = compositor.CreateMaskBrush();
maskBrush.Mask = mask; //计算阴影的颜色
Vector3 shadowColor = background - (background - new Vector3(0, 0, 0)) * opacity;
shadowColor = Vector3.Max(Vector3.Zero, shadowColor);
shadowColor += (background - shadowColor) * i / depth; maskBrush.Source = compositor.CreateColorBrush(Color.FromArgb(255, (byte)shadowColor.X, (byte)shadowColor.Y, (byte)shadowColor.Z));

4. 实际应用

就只是一个静态的长阴影的话,那还不如用PS做成图片在放进UWP里。GetAlphaMask另一个好处是它并不仅获取静态的轮廓,而是一直和源头同步。这样可玩性就大多了,例如我把长阴影的设计元素添加到番茄钟里面,成果如下:

5. 结语

虽然长阴影已经有点过时了,但自己做起来还是觉得很酷很酷。刚开始还担心这样搞性能会很差,实际运行起来后发觉超级OK。上面的动画可以安装我的番茄钟应用试玩一下,安装地址:

一个番茄钟

6. 参考

[ContainerVisual Class (Windows.UI.Composition) - Windows UWP applications Microsoft Docs]((https://docs.microsoft.com/en-us/uwp/api/windows.ui.composition.containervisual)

VisualCollection Class (Windows.UI.Composition) - Windows UWP applications Microsoft Docs

Vector3 Struct (Windows.Foundation.Numerics) - Windows UWP applications Microsoft Docs

7. 源码

OnePomodoro_LongShadow.xaml.cs at master

最新文章

  1. PHP的单态类——为了产生唯一的对象
  2. web前端开发和后端开发有什么区别?
  3. Centos7的安装、Docker1.12.3的安装,以及Docker Swarm集群的简单实例
  4. select在各个浏览器中的兼容性问题
  5. BZOJ-1036 树的统计Count 链剖线段树(模板)=(树链剖分+线段树)
  6. 关于Win7图标丢失、不正常显示的修复方法
  7. SqlServer主键外键添加及判断表是否存在
  8. 夺命雷公狗---DEDECMS----6快速入门之总结篇
  9. hdu 4643(计算几何)
  10. 在数据库各种状态下查询DBID的五大类十种方法汇总
  11. Android Touch事件传递机制
  12. lua package.path的使用
  13. c++学习_2
  14. 第三天 Java语言基础
  15. 为什么Elasticsearch查询变得这么慢了?
  16. phpstudy如何安装ssl证书
  17. asp.net mvc 实现上传文件带进度条
  18. java虚拟机学习
  19. mfc 虚函数
  20. Centos7下CPU内存等资源监控

热门文章

  1. Spring 梳理-跨重定向请求传递数据-Flash
  2. windows安装Mycat并测试
  3. RBD 基本使用 - Storage6
  4. 算法题解:最大或最小的K个数(海量数据Top K问题)
  5. PSSH工具
  6. dedecms5.7最新漏洞修复
  7. Android 调用 WebService
  8. docker镜像命令使用
  9. 在chrome浏览器中调用IE浏览器并访问(openIE.reg自定义协议)
  10. Vue-CLI项目快速UI布局-element-ui