您好,自定义渲染器!
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属性的文本。
这是在三个标准平台上运行的程序:
注意如何通过使用HelloView对象上设置的常规HorizontalOptions和VerticalOptions属性来正确居中文本。 但是,您无法在HelloView上设置HorizontalTextAlignment和VerticalTextAlignment属性。 这些属性由Label定义,而不是由HelloView定义。
要将HelloView转换为用于显示文本的完整视图,您需要开始向HelloView类添加属性。 让我们来看看如何使用不同的示例将属性添加到渲染器。