第二十七章:自定义渲染器(二)

简介: 您好,自定义渲染器!HelloRenderers程序主要演示编写简单渲染器所需的开销。 该程序定义了一个名为HelloView的新View衍生,旨在显示一个简单的固定文本字符串。 这是HelloRenderers可移植类库项目中的完整HelloView.cs文件:using Xamarin.Forms;namespace HelloRenderers{ public class HelloView : View { }}而已! 但请注意,该类被定义为public。

您好,自定义渲染器!

HelloRenderers程序主要演示编写简单渲染器所需的开销。 该程序定义了一个名为HelloView的新View衍生,旨在显示一个简单的固定文本字符串。 这是HelloRenderers可移植类库项目中的完整HelloView.cs文件:

using Xamarin.Forms;
namespace HelloRenderers
{
    public class HelloView : View 
    {
    }
}

而已! 但请注意,该类被定义为public。 即使您可能认为此类仅在PCL中引用,但事实并非如此。 它必须对平台组件可见。
HelloRenderers PCL非常简单,甚至不会打扰页面类。 相反,它实例化并在App.cs文件中显示以页面为中心的HelloView对象:

namespace HelloRenderers
{
    public class App : Application
    {
        public App()
        {
            MainPage = new ContentPage
            {
                Content = new HelloView
                {
                    VerticalOptions = LayoutOptions.Center,
                    HorizontalOptions = LayoutOptions.Center
                }
            };
        }
    __
    }
}

没有任何其他代码,这个程序运行正常,但你实际上不会在屏幕上看到HelloView对象,因为它只是一个空白的透明视图。 我们需要的是HelloView的一些平台渲染器。
当Xamarin.Forms应用程序启动时,Xamarin.Forms使用.NET反射搜索构成应用程序的各种程序集,查找名为ExportRenderer的程序集属性。 ExportRenderer属性指示是否存在可以为Xamarin.Forms元素提供支持的自定义渲染器。
HelloRenderers.iOS项目包含以下HelloViewRenderer.cs文件,完整显示。 请注意using指令下的ExportRenderer属性。 因为这是一个程序集属性,所以它必须在名称空间声明之外。 这个特殊的ExportRenderer属性基本上表示“HelloViewRenderer类型的渲染器支持HelloView类”:

using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using UIKit;
using HelloRenderers;
using HelloRenderers.iOS;
[assembly: ExportRenderer(typeof(HelloView), typeof(HelloViewRenderer))]
namespace HelloRenderers.iOS
{
    public class HelloViewRenderer : ViewRenderer<HelloView, UILabel>
    {
        protected override void OnElementChanged(ElementChangedEventArgs<HelloView> args)
        {
            base.OnElementChanged(args);
            if (Control == null)
            {
                UILabel label = new UILabel
                {
                    Text = "Hello from iOS!",
                    Font = UIFont.SystemFontOfSize(24)
                };
                SetNativeControl(label);
            }
        }
    }
}

HelloViewRenderer类的定义遵循ExportRenderer属性。这堂课必须公开。它派生自通用的ViewRenderer类。这两个通用参数名为TView,它是Xamarin.Forms类,TNativeView是这个特殊情况下的类,是iOS的原生类。
在iOS中,显示文本的类是UIKit名称空间中的UILabel,这就是这里使用的内容。 ViewRenderer的两个泛型参数基本上说“一个HelloView对象实际上被渲染为iOS UILabel对象”。
ViewRenderer派生的一个基本工作是覆盖OnElementChanged方法。创建HelloView对象时调用此方法,其作用是创建用于呈现HelloView对象的本机控件。
OnElementChanged覆盖首先检查该类是否继承自ViewRenderer的Control属性。此Control属性由ViewRenderer定义为TNativeView类型,因此在HelloViewRenderer中它的类型为UILabel。第一次调用OnElementChanged时,此Control属性将为null。必须创建UILabel对象。这就是该方法的作用,为其分配一些文本和字体大小。然后将该UILabel方法传递给SetNativeControl方法。此后,Control属性将是此UILabel对象。
文件顶部的using指令分为三组:

  • ExportRenderer属性需要Xamarin.Forms命名空间的using指令,而ViewRenderer类需要Xamarin.Forms.Platform.iOS。
  • UILabel需要iOS UIKIt名称空间。
  • 仅对于ExportRenderer属性中的HelloView和HelloViewRenderer引用,需要HelloRenderers和HelloRenderers.iOS的using指令,因为该属性必须位于HelloRenderer.iOS命名空间块之外。

最后两个使用指令特别烦人,因为它们只需要一个目的。 如果您愿意,可以通过完全限定ExportRenderer属性中的类名来删除这两个使用指令。
这在以下渲染器中完成。 这是HelloRenderers.Droid项目中的完整HelloViewRenderer.cs文件。 用于显示文本的Android小部件是Android.Widget命名空间中的TextView:

using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Android.Util;
using Android.Widget;
[assembly: ExportRenderer(typeof(HelloRenderers.HelloView),
 typeof(HelloRenderers.Droid.HelloViewRenderer))]
namespace HelloRenderers.Droid
{
    public class HelloViewRenderer : ViewRenderer<HelloView, TextView>
    {
        protected override void OnElementChanged(ElementChangedEventArgs<HelloView> args)
        {
            base.OnElementChanged(args);
            if (Control == null)
            {
                SetNativeControl(new TextView(Context)
                {
                    Text = "Hello from Android!"
                });
                Control.SetTextSize(ComplexUnitType.Sp, 24);
            }
        }
    }
}

此HelloViewRenderer类派生自Android版本的ViewRenderer。 ViewRenderer的泛型参数表明Android TextView小部件支持HelloView类。
再次,在第一次调用OnElementChanged时,Control属性将为null。该方法必须创建本机Android TextView小部件并调用SetNativeControl。为了节省一点空间,新实例化的TextView对象直接传递给SetNativeControl方法。请注意,TextView构造函数需要Android Context对象。这是OnElementChanged的属性。
在调用SetNativeControl之后,ViewRenderer定义的Control属性是本机Android小部件,在本例中是TextView对象。该方法使用此Control属性在TextView对象上调用SetTextSize。在Android中,文本大小可以通过多种方式进行缩放。 ComplexUnitType.Sp枚举成员表示“缩放像素”,它与Xamarin.Forms处理Android中Label的字体大小的方式兼容。
这是HelloRenderers.UWP项目中的HelloViewRenderer的UWP版本:

using Xamarin.Forms.Platform.UWP;
using Windows.UI.Xaml.Controls;
[assembly: ExportRenderer (typeof(HelloRenderers.HelloView), 
 typeof(HelloRenderers.UWP.HelloViewRenderer))]
namespace HelloRenderers.UWP
{
    public class HelloViewRenderer : ViewRenderer<HelloView, TextBlock>
    {
        protected override void OnElementChanged(ElementChangedEventArgs<HelloView> args)
        {
            base.OnElementChanged(args);
            if (Control == null)
            {
                SetNativeControl(new TextBlock
                {
                    Text = "Hello from the UWP!",
                    FontSize = 24,
                });
            }
        }
    }
}

在所有Windows平台中,HelloView对象由Windows.UI.Xaml.Controls命名空间中的Windows运行时TextBlock呈现。
HelloRenderers.Windows和HelloRenderers.WinPhone项目中的HelloViewRenderer类大致相同,除了名称空间和用于设置TextBlock的Text属性的文本。
这是在三个标准平台上运行的程序:
2019_06_03_131710
注意如何通过使用HelloView对象上设置的常规HorizontalOptions和VerticalOptions属性来正确居中文本。 但是,您无法在HelloView上设置HorizontalTextAlignment和VerticalTextAlignment属性。 这些属性由Label定义,而不是由HelloView定义。
要将HelloView转换为用于显示文本的完整视图,您需要开始向HelloView类添加属性。 让我们来看看如何使用不同的示例将属性添加到渲染器。

目录
相关文章
|
前端开发
Threejs - 加载视频纹理渲染 实现一个3D视频播放器
Threejs - 加载视频纹理渲染 实现一个3D视频播放器
2155 0
Threejs - 加载视频纹理渲染 实现一个3D视频播放器
|
3月前
|
JavaScript 前端开发
使用 WebGL 创建 3D 动画
【10月更文挑战第3天】使用 WebGL 创建 3D 动画
|
8月前
|
Python
渲染模板
【2月更文挑战第21天】渲染模板。
31 1
【Redshift渲染器渲染出图片有色差(红移渲染器)】
【Redshift渲染器渲染出图片有色差(红移渲染器)】
211 0
【Redshift渲染器渲染出图片有色差(红移渲染器)】
|
存储 资源调度 JavaScript
2.Vue3中Cesium地图初始化及地图控件配置
本文中,我们主要介绍 Cesium 在 Vue 3运行环境的配置,以及 Cesium 实例中控件的显隐设置,本文是后续文章内容的基础,项目代码在此查看;通过本文,我们可以得到一个纯净的 cesium 项目,后续的操作我们就可以在此基础上进行;
695 0
Sprite渲染流程-纹理绑定
Sprite渲染流程-纹理绑定
98 0
|
人工智能 前端开发 JavaScript
canvas 中如何实现自定义路径动画
前言 大家好!!又到周末了,最近项目忙完了,有时间写文章了。之前有粉丝问我, fly哥怎么实现自定义路径动画, 当时给他说的就是路径无非不就是直线 或者曲线。也就这两种, 直线的话 可以用直线方程, 曲线的话稍微复杂点 ,需要用贝塞尔曲线去做lerp。也就是动画的每一幁的算出路径的对应的坐标就可以了。但是这套方案学习成本太高了, 有没有一种更加简单的方式呢?本篇文章大概花费你5分钟, 你可以学到什么呢 svg 的 两个无敌api 后面介绍 封装了一个自定义路径动画函数 创建Path 制作动画前,先要拿到动画的路径,对此我们可以直接使用svg的path定义规则,比如我们定义了一条较为复杂的路径
canvas 中如何实现自定义路径动画
|
Dart 开发者
【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )(三)
【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )(三)
189 0
【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )(三)
|
JavaScript
vue 动态组件动画-转场动画基础
这个先不用单文件组件来演示 因为单文件组件 一般都是项目使用了,项目中一般都是路由动画
318 0
【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )(二)
【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )(二)
179 0

热门文章

最新文章