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

Xamarin.Forms的核心可能看起来很神奇:像Button这样的单个元素在iOS,Android和Windows操作系统下显示为本机按钮的能力。在本章中,您将看到如何在所有三个平台上的Xamarin.Forms中的每个元素都由称为渲染器的特殊类支持。例如,Xamarin.Forms中的Button类由各种平台中的几个类支持,每个类都名为ButtonRenderer。
好消息是你也可以编写自己的渲染器,本章将向你展示如何。但是,请记住,编写自定义渲染器是一个很大的主题,本章只能帮助您入门。
编写自定义渲染器并不像编写Xamarin.Forms应用程序那么容易。您需要熟悉各个iOS,Android和Windows运行时平台。但显然它是一种强大的技术。实际上,一些开发人员认为Xamarin.Forms的最终价值在于提供一个编写自定义渲染器的结构化框架。

完整的类层次结构

在第11章“可绑定基础结构”中,您看到了一个名为ClassHierarchy的程序,它显示了Xamarin.Forms类层次结构。 但是,该程序仅显示Xamarin.Forms.Core和Xamarin.Forms.Xaml程序集中的类型,这些程序集是Xamarin.Forms应用程序通常使用的类型。
Xamarin.Forms还包含与每个平台关联的其他程序集。 这些程序集通过为Xamarin.Forms提供平台支持(包括所有渲染器)起着至关重要的作用。
您可能已经熟悉了这些程序集的名称,可以在Xamarin.Forms解决方案的各个项目的Reference部分中看到它们:

  • Xamarin.Forms.Platform(非常小)
  • Xamarin.Forms.Platform.iOS
  • Xamarin.Forms.Platform.Android
  • Xamarin.Forms.Platform.UAP
  • Xamarin.Forms.Platform.WinRT(大于此列表中的下两个)
  • Xamarin.Forms.Platform.WinRT.Tablet
  • Xamarin.Forms.Platform.WinRT.Phone

在本讨论中,这些将统称为平台组件。
是否可以编写一个Xamarin.Forms应用程序,在这些平台程序集中显示类型的类层次结构?
是! 但是,如果您仅限于检查通常使用应用程序加载的程序集 - 这当然是最简单的方法 - 那么应用程序只能显示属于该应用程序的程序集中的类型。 例如,您只能使用在iOS下运行的Xamarin.Forms程序在Xamarin.Forms.Platform.iOS程序集中显示类型,对于其他程序集也是如此。
但是仍然存在一个问题:您可能还记得,最初的ClassHierarchy程序首先是根据它知道的两个类(View和Extensions)获取Xamarin.Forms.Core和Xamarin.Forms.Xaml程序集的.NET程序集对象。 在这两个集会中:

typeof(View).GetTypeInfo().Assembly
typeof(Extensions).GetTypeInfo().Assembly

但是,Xamarin.Forms应用程序的可移植类库无法直接访问平台程序集。 平台程序集仅由应用程序项目引用。 这意味着Xamarin.Forms可移植类库不能使用类似的代码来获取对平台程序集的引用。 这不起作用:

typeof(ButtonRenderer).GetTypeInfo().Assembly

但是,这些平台程序集在应用程序运行时会加载,因此PCL可以根据程序集名称获取平台程序集的Assembly对象。 PlatformClassHierarchy程序如下所示:

public partial class PlatformClassHierarchyPage : ContentPage
{
    public PlatformClassHierarchyPage()
    {
        InitializeComponent();
        List<TypeInformation> classList = new List<TypeInformation>();
        string[] assemblyNames = Device.OnPlatform(
        iOS: new string[] { "Xamarin.Forms.Platform.iOS" },
        Android: new string[] { "Xamarin.Forms.Platform.Android" },
        WinPhone: new string[] { "Xamarin.Forms.Platform.UAP",
                                 "Xamarin.Forms.Platform.WinRT",
                                 "Xamarin.Forms.Platform.WinRT.Tablet",
                                 "Xamarin.Forms.Platform.WinRT.Phone" }
        );
        foreach (string assemblyName in assemblyNames)
        {
            try
            {
                Assembly assembly = Assembly.Load(new AssemblyName(assemblyName));
                GetPublicTypes(assembly, classList);
            }
            catch
            {
            }
        }
        __
}

从那里,PlatformClassHierarchy程序与原始的ClassHierarchy程序相同。
如您所见,foreach循环从静态Assembly.Load方法获取Assembly对象。 但是,程序无法直接确定它是在通用Windows平台还是其他Windows运行时平台下运行,因此如果Device.OnPlatform指示它是WinPhone设备,程序将尝试所有四个程序集并使用try 并抓住只是忽略那些不起作用的。
一些类名 - 特别是程序集外部类的完全限定类名 - 对于纵向显示而言有点太长并且包装不好,但这是三个平台上显示的一部分。 每个都已滚动到以通用ViewRenderer类开头的类层次结构的一部分。 这通常是您创建自己的自定义渲染器的类:
第二十七章:自定义渲染器(一)
注意ViewRenderer类的通用参数,名为TView和TNativeView,或TElement和TNativeElement:正如您将看到的,TView或TElement是Xamarin.Forms元素,如Button,而TNativeView或TNativeElement是该Button的本机控件。。
虽然PlatformClassHierarchy程序没有指明这一点,但ViewRenderer泛型参数的约束依赖于平台:

  • 在iOS上:
  1. TView受限于Xamarin.Forms.View

o TNativeView受限于UIKit.UIView

  • 在Android上:
  1. TView受限于Xamarin.Forms.View

o TNativeView受限于Android.Views.View

  • 在Windows平台上:
  1. TElement受限于Xamarin.Forms.View

o TNativeElement受限于Windows.UI.Xaml.FrameworkElement

要编写自定义渲染器,可以从ViewRenderer派生一个类。 要适应所有平台,您必须使用从UIView派生的类来实现iOS渲染器,使用从View派生的类实现Android渲染器,并使用派生自FrameworkElement的类实现Windows平台的渲染器。
我们来试试吧!

上一篇:entity framework自动生成数据库外键“表名_外键”的解决方案


下一篇:网络视频直播平台用户调查该从哪几个方面入手