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

简介: 您好,自定义渲染器!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类添加属性。 让我们来看看如何使用不同的示例将属性添加到渲染器。

目录
相关文章
|
存储
CocosCreator3.8研究笔记(二十二)CocosCreator 动画系统-动画剪辑和动画组件介绍
CocosCreator3.8研究笔记(二十二)CocosCreator 动画系统-动画剪辑和动画组件介绍
319 0
|
3月前
|
前端开发 JavaScript 数据可视化
使用React的函数式组件实现一个具有过渡变化、刻度切换、点击高亮的柱状图DIY组件
本文展示了如何使用React的函数式组件实现一个具有过渡变化、刻度切换、点击高亮效果的自定义柱状图组件,并提供了完整的示例代码和实现效果。
70 1
使用React的函数式组件实现一个具有过渡变化、刻度切换、点击高亮的柱状图DIY组件
|
6月前
|
JavaScript atlas Kotlin
深度解读dragonBones使用SpriteFrame任意换肤的实现
深度解读dragonBones使用SpriteFrame任意换肤的实现
122 0
|
6月前
|
JavaScript 前端开发
使用styled-components控制主题切换(有手就行)
使用styled-components控制主题切换(有手就行)
132 0
|
JavaScript 定位技术
WebGis——Pixi开发vue项目之使用遮罩实现图形缓慢填充颜色(三)
WebGis——Pixi开发vue项目之使用遮罩实现图形缓慢填充颜色(三)
|
数据可视化 前端开发
【React工作记录四十二】获取页面的可视化高度和宽度
【React工作记录四十二】获取页面的可视化高度和宽度
308 0
|
数据可视化 前端开发
#yyds干货盘点# 【React工作记录四十二】获取页面的可视化高度和宽度
#yyds干货盘点# 【React工作记录四十二】获取页面的可视化高度和宽度
215 0
#yyds干货盘点# 【React工作记录四十二】获取页面的可视化高度和宽度
|
前端开发
实例|APICloud AVM框架封装滑动单元格组件
滑动单元格组件原理是主题部分把按钮进行遮挡,按钮通过绝对定位,定位在最右边,通过监听触摸事件(touch),判断滑动的方向和计算滑动的距离以此来判定显示和隐藏按钮。
176 0
|
物联网
ThingJS有4种技术实现对象拾取方式
对象的拾取,这是3D技术的一个专业术语。
ThingJS有4种技术实现对象拾取方式
第二十七章:自定义渲染器(六)
有趣的是,Android SeekBar小部件具有与Steps属性等效的功能,但不等同于Minimum和Maximum属性! 这怎么可能? SeekBar实际上定义了一个名为Max的整数属性,SeekBar的Progress属性始终是一个从0到Max的整数。
763 0