在上一篇中,老周用一个示例,演示了框架视图的创建过程,在本篇中,老周将给大伙伴们说一下 Composition 构建 UI 的一些“零件”。

UI Composition 有一个核心类——对,就是 Compositor 类,它是总生产车间,组成 UI 的各种元素都可以由它来创建,所以,你会看到,它公开了 K 个以 Create 开头的方法。我们在组建 UI 时所用到的各种元素都可以调用这些以 Create 打头的方法来创建。

要让用户在窗口上看到你所构建的 UI 元素,可视化树中至少需要一 Visual 对象。Visual 是一个基类,在组成可视化树时,我们有三种 Visual 可以用。

第一种是 ContainerVisual,它表示一容器,可以向它的 Children 集合中添加子元素,以构建复杂的可视化对象。

第二种是 SpriteVisual,它从 ContainerVisual 类派生,所以也支持添加子元素。Sprite 是“小仙女”的意思,表明这个类不仅仅是个容器,它自身就可以绘制可视化内容,所以这个类用得还是比较多的。它主要公开了 Brush 属性,可以使用各种画刷来绘制内容。比如,单种颜色填充的画刷,渐变画刷,绘制图形的画刷等。

第三种是  LayerVisual,它也是容器元素,它类似于在视图中创建一个图层,并可以在其中继续添加子元素。

要呈现多彩灿烂的内容,你需要画刷,因此,UI Compositon 提供各种用途的画刷。

1、单色画刷,只有一种颜色对对定可视化元素进行填充。

2、渐变画刷,可以设置多种颜色过度。

3、Drawing Surface ,这个强大,相当于一块自由画布,你可以在上面画各种东东。你可以画文本,画圆形,画线,画大象,画野鸭子。甚至你可以在上面画一个正在播放的视频。绘制代码是要用C++来写,不过我们可以结合 Win 2D 组件一起用,这个老周后面会绘出例子的。

4、效果画刷。这种画刷主要用来产生一些视觉效果,比如模糊、锐化、颜色叠加、反相等等。

有了可视化对象和画刷,我们基本上可以弄出很多东西来。不过,可能大伙伴们会想了,要是能模拟一些真实场景就更佳了。于是,灯光就出场了。灯光就是模拟我们现实世界中的各种光源,比如小灯泡发出的点光,手电筒照射的光,或者照射范围更大的环境光(如白炽灯)等。

1、SpotLight,这种光源有点像手电筒的光,发散出去后会产生一个锥形区域。

2、PointLight,类似于一盏小灯泡,光源是一个点,但它可以向四周照射。

3、DistantLight,这种光有点像汽车的远光灯(晚上开车时别乱开远光啊,会害死人的),也像太阳光。总之,这种光源照射面很大,而且光很强,传播距离远。

4、AmbientLight,这种光就像你家里,房间里安装的白炽灯,或者是新型的节能灯,白白的光,可以照亮整个屋子,即环境光。

老周这么一说,你一定会觉得没意思,都不知道灯光照起来是什么效果。别急,老周后面会给例子的,你会看到效果的。

有刷子,有灯泡,有画布,你大概觉得差不多了,可以画出很多大作了。是的,不过,要是你的大作能够动起来,是不是更生动了呢。比如你画了猪八戒,手里拿着个大西瓜,要是能让八戒动起来,尤其是嘴巴,一下一下地啃西瓜皮,那该多好。因此,你还需要动画。

1、关键帧动画。这个应该好懂,就是可以在某个时刻设置一个关键帧,然后关键帧之间会自动以时间为基准产生过度动画。

2、表达式。即使用一个计算公式来生成动画所需要的值。比如你要对可视化元素的不透明度进行动画处理,输入 Opacity * 0.5,表示每次的不透明度变化,最终值都是上一次计算结果的一半,比如,不透明度为 100%,进行动画后变成 50%,再进行一次动画后就成 25% …… 要注意的是,表达式产生的动画是不能控制时间的。

以上内容你不必太认真看,就当作常识,大致涉猎一下就 OK 了,后续的博文中,老周会逐个介绍的。接下来,我们要了解一下如何构建 UI 树。

咱们一起来动动手,学习编程一定要动手的(当然,动脑子是必须的),如果你能用脚打字,也可以动脚。

记得老周一一篇中说过的吧,我们要先实现自己的一个视图,即实现 IFrameworkView 接口。

class DemoView : IFrameworkView
{
……
}

然后,我们声明几个私有字段。

        Compositor mCompositor = null;
CoreWindow mWindow = null;
SpriteVisual rootVisual = null;

要组装 UI 构件,我们需要一个 Compositor 类的实例,在这个例子中,我打算用 SpriteVisual 作为 UI 树的根,它既可以用画刷绘制内容,也可以添加子元素,正可谓是一物两用。

接着,进行初始化,此时我们可以实例化 Compositor 对象,或者实例化其他我们需要的东西。注意此时不要组建 UI 树,因为窗口还未初始化,此时建UI树会发生异常。

        public void Initialize(CoreApplicationView applicationView)
{
mCompositor = new Compositor();
}

Load方法我们这里没啥要加载的,就留空吧。

        public void Load(string entryPoint)
{
// 留着以后用来养金鱼
}

接下来是重点,SetWindow 方法,此时窗口已经可用,所以此时可以组建 UI 树了。

        public void SetWindow(CoreWindow window)
{
mWindow = window;
// 创建根元素
rootVisual = mCompositor.CreateSpriteVisual(); // 这个是重点,必须要有这个 target
CompositionTarget target = mCompositor.CreateTargetForCurrentView();
// 指定 UI 根元素
target.Root = rootVisual; // 这时候UI元素上是空白的
// 为了能看到东西,我们画点东西上去
CompositionColorBrush backBrush = mCompositor.CreateColorBrush(Colors.Blue);
rootVisual.Brush = backBrush;
}

这里有一个很重要的东东,大伙要严重注意。在组建 UI 时,你必须调用 CreateTargetForCurrentView 方法创建一个 CompositionTarget 实例,它直接与当前的应用程序视图关联的,你必须创建一个该实例,然后再把 UI 的根元素赋值给 CompositionTarget 的 Root 属性。Root 属性引用的UI元素就作为整个视图的根。

而且,这个 target 在整个视图的生命周期内,你只能创建一次,如果设置了根元素后,你还调用 CreateTargetForCurrentView 方法的话,你会收到一条 DCOMPOSITION_ERROR_WINDOW_ALREADY_COMPOSED 错误,该错误提醒你,该可视化树已经组装过了,你不能再调用了。

CreateColorBrush 方法创建一个单色填充的画刷,这里我用的是蓝色。

在 Run 方法中开启消息循环。

        public void Run()
{
mWindow.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessUntilQuit);
}

但是,以上代码漏了一句,所以一旦运行,你只能看到初始屏幕。如下图。

因为你还没有激活当前窗口,故你在 ProcessEvents 之前,要加上这一句。

        public void Run()
{
mWindow.Activate();
mWindow.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessUntilQuit);
}

因为我用 mWindow 字段引用了当前窗口的实例(就是刚刚上面的 SetWindow 方法中),所以我直接调用 Activate 方法。如果你没有用变量存储当前窗口的实例,你还可以这样调用。

 CoreWindow.GetForCurrentThread().Activate();

最后,在视图销毁时,打扫一下卫生。

        public void Uninitialize()
{
rootVisual.Dispose();
mCompositor.Dispose();
mWindow = null;
}

视图的逻辑弄完了,再实现一下 IFrameworkViewSource 接口。

    class DemoViewSource : IFrameworkViewSource
{
public IFrameworkView CreateView()
{
return new DemoView();
}
}

别忘了入口点。

    class Program
{
static void Main()
{
CoreApplication.Run(new DemoViewSource());
}
}

好,大功告成!按下【F5】键,你满怀信心地看着程序启动。结果傻眼了,FK!怎么一片空白的?

咋回事呢?是啊,咋回事呢。再检查一下代码,逻辑都对啊。其实,你之所以看不到东西,是因为可视化元素的大小默认是 0,所以,你要回到 SetWindow 方法,给可视化元素设一个 Size。

        public void SetWindow(CoreWindow window)
{
mWindow = window;
// 创建根元素
rootVisual = mCompositor.CreateSpriteVisual();
rootVisual.Size = new System.Numerics.Vector2(300f, 320f);
……
}

如果必要,你还可以设置视图对象的偏移量,默认是 0、0、0,即位于窗口的左上角,注意这个坐标是三个值的,即XYZ三个轴,X和Y轴你都懂的,原点在左上角,X轴正方向往右,Y轴正方向往下。至于Z轴嘛,从屏幕里面向外,说白了就是正方向指着你。

可以设置一下偏移量。

        public void SetWindow(CoreWindow window)
{
mWindow = window;
// 创建根元素
rootVisual = mCompositor.CreateSpriteVisual();
rootVisual.Size = new System.Numerics.Vector2(300f, 320f);
rootVisual.Offset = new System.Numerics.Vector3(0f, 20f, 5f);

……
}

好了,一切的疑问都解开了。再运行一下,Good,效果出来了。

其实,你还可以让它带透明效果的,方法和 XAML 中一样。

        public void SetWindow(CoreWindow window)
{
……
rootVisual = mCompositor.CreateSpriteVisual();
rootVisual.Size = new System.Numerics.Vector2(300f, 320f);
rootVisual.Offset = new System.Numerics.Vector3(0f, 20f, 5f);
rootVisual.Opacity = 0.5f;
……
}

再看看效果。

有趣吧,你还可以对它进行旋转的。

 rootVisual.RotationAngleInDegrees = 60f;

RotationAngle 属性设置的旋转角度是弧度角,要用角度进行设置,就用 RotationAngleInDegrees 属性。

你不过瘾的话,还可以调整整个三维坐标的方向。

  rootVisual.Orientation = new System.Numerics.Quaternion(-15f, 5f, 2f, 1f);

然后就变成这个样子了。

怎么样,有意思吧。本篇就扯到这里,大伙伴只要知道UI元素的组装方法就可以了,至于说那些三维变量如何设置,这个可以网上查资料,或者自己摸索,三维方面的东西还是挺复杂,其实老周也不是很了解,写出来大家交流交流而已。

【Win 10 应用开发】UI Composition 札记(二):基本构件的更多相关文章

  1. 【Win 10 应用开发】UI Composition 札记(一):视图框架的实现

    在开始今天的内容之前,老周先说一个问题,这个问题记得以前有人提过的. 设置 Windows.ApplicationModel.Core.CoreApplicationView.TitleBar.Ext ...

  2. 【Win 10 应用开发】UI Composition 札记(三):与 XAML 集成

    除了 DirectX 游戏开发,我们一般很少单独使用 UI Composition ,因此,与 XAML 互动并集成是必然结果.这样能够把两者的优势混合使用,让UI布局能够更灵活. 说到与 XAML ...

  3. 【Win 10 应用开发】UI Composition 札记(四):绘制图形

    使用 Win 2D 组件,就可以很轻松地绘制各种图形,哪怕你没有 D2D 相关基础,也不必写很复杂的 C++ 代码. 先来说说如何获取 Win 2D 组件.很简单,创建 UWP 应用项目后,你打开“解 ...

  4. 【Win 10 应用开发】UI Composition 札记(五):灯光

    UI Composition 除了能够为 UI 元素建立三维空间外,还有相当重要的一个部件——灯光.宇宙万物的精彩缤纷,皆源于光明,光,使我们看到各种东西,除了黑洞之外的世界都是五彩斑谰的.故而,真要 ...

  5. 【Win 10 应用开发】UI Composition 札记(六):动画

    动画在 XAML 中也有,而且基本上与 WPF 中的用法一样.不过,在 UWP 中,动画还有一种表现方式—— 通过 UI Composition 来创建. 基于 UI Composition 的动画, ...

  6. 【Win 10 应用开发】启动远程设备上的应用

    这个功能必须在“红石-1”(build 14393)以上的系统版中才能使用,运行在一台设备上的应用,可以通过URI来启动另一台设备上的应用.激活远程应用需要以下前提: 系统必须是build 14393 ...

  7. 【Win 10应用开发】Adaptive磁贴模板的XML文档结构

    在若干天之前,老周给大家讲了Adaptive Toast通知的XML模板,所以相应地,今天老周给大家介绍一下Adaptive磁贴的新XML模板. 同样道理,你依旧可以使用8.1时候的磁贴模板,在win ...

  8. 【Win 10应用开发】认识一下UAP项目

    Windows 10 SDK预览版需要10030以上版本号的Win 10预览版系统才能使用.之前我安装的9926的系统,然后安装VS 2015 CTP 6,再装Win 10 SDK,但是在新建项目后, ...

  9. 【Win 10 应用开发】在代码中加载文本资源

    记得前一次,老周给大伙,不,小伙伴们介绍了如何填写 .resw 文件,并且在 XAML 中使用 x:Uid 标记来加载.也顺便给大伙儿分析了运行时是如何解析 .resw 文件的. 本来说好了,后续老周 ...

随机推荐

  1. adobe acrobat pro 9破解方法

    方法一:(经常没用,不推荐) 尝试一下部分常见序列号: 网上搜 方法二: (能找到文件的,推荐) 1.到 C:\Program Files\Common Files\Adobe\Adobe PCD\c ...

  2. PLT文件 和 DXF文件

    PLT: CAM/CAD类似软件处理的图像文件的文件格式 DXF: AutoCAD(Drawing Interchange Format或者Drawing Exchange Format) 绘图交换文 ...

  3. 80端口被system 占用

    1 运行'netstat -ano'发现80端口被pid=4的进程占用 2 打开任务管理器,发现pid=4的进程,其实是system进程,其对应的进程描述是NT kernel & system ...

  4. JAVAWEB复习资料-01

    CSS中@import和link两种插入样式表方式有什么不同? 1.link属于HTML标签,除了引入css文件之外还能定义RSS等,而@import只能用于加载CSS. 2.link在引用CSS时, ...

  5. 命令行参数处理-getopt()和getopt_long()

    在实际编程当中,自己编写代码处理命令行参数是比较麻烦且易出错的.一般我们会直接使用getopt()和getopt_long()函数,下文将介绍具体的使用方法. getopt() getopt()用于处 ...

  6. 原生JS封装animate运动框架

    <!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8" ...

  7. iOS在类内部怎么访问实例变量比较好?

    OC在类文件的内部访问实例变量,有直接访问和使用getter/setter方法访问两种方式,它们的区别有: 1.直接访问不经过OC的方法分发(method dispatch),所以访问速度比较快,在这 ...

  8. open() close()

    open() 方法可以查找一个已经存在或者新建的浏览器窗口. 语法: window.open([URL], [窗口名称], [参数字符串]) 每个参数必须用引号 参数说明: URL:可选参数,在窗口中 ...

  9. MVC调用部分视图PartialView

    using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Demo2 ...

  10. SqlServer2008 导入导出txt或Execl数据

    --右键user表所在的数据库,然后任务--导出数据,然后根据提示设置就行 --从txt中导入 EXEC master..xp_cmdshell 'bcp Northwind.dbo.sysusers ...