• 【Win 10 应用开发】UI Composition 札记(二):基本构件


    在上一篇中,老周用一个示例,演示了框架视图的创建过程,在本篇中,老周将给大伙伴们说一下 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元素的组装方法就可以了,至于说那些三维变量如何设置,这个可以网上查资料,或者自己摸索,三维方面的东西还是挺复杂,其实老周也不是很了解,写出来大家交流交流而已。

  • 相关阅读:
    SOAP协议调研
    android 支付宝 沙箱环境配置
    点击两次物理键退出APP
    Android LitePal的简单使用
    多线程
    【Android】15.0 UI开发(六)——列表控件RecyclerView的网格布局排列实现
    【Android】14.0 UI开发(五)——列表控件RecyclerView的瀑布布局排列实现
    【Android】利用回收机制创建ListView列表实现
    BaseActivity
    【MySQL数据库】一些bug的解决
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/7784024.html
Copyright © 2020-2023  润新知