游乐游手机版
首页/AI教程/文章详情

自定义渲染器开发教程第二部分

时间:2026-05-30 09:09
自定义渲染器入门:从HelloRenderers开始 先来介绍一下HelloRenderers这个示例程序。它的核心目标非常明确——就是让你直观地了解,编写一个最简单的自定义渲染器究竟需要完成哪些步骤。在这个示例中,我们定义了一个名为HelloView的新视图,它继承自View,唯一的功能就是在屏幕

自定义渲染器入门:从HelloRenderers开始

先来介绍一下HelloRenderers这个示例程序。它的核心目标非常明确——就是让你直观地了解,编写一个最简单的自定义渲染器究竟需要完成哪些步骤。在这个示例中,我们定义了一个名为HelloView的新视图,它继承自View,唯一的功能就是在屏幕上显示一段固定的文本字符串。

首先来看PCL(可移植类库)中的完整代码,整个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只是一个完全透明且没有任何绘制内容的视图,缺少相应的渲染器来告诉它应该以何种方式呈现。

关键点就在这里:当Xamarin.Forms应用启动时,它会通过.NET反射扫描所有程序集,寻找标注了ExportRenderer特性的位置。这个特性就像信标一样,告诉框架:“嘿,这里有一个自定义渲染器,可以为特定的Xamarin.Forms元素提供渲染支持”。

接下来看看iOS项目中的HelloViewRenderer.cs文件。请注意在using语句之后,紧接着就是ExportRenderer特性。由于它是程序集级别的特性,因此必须放在命名空间声明的外部。它的含义非常直接:“HelloView这个类,由HelloViewRenderer这个渲染器负责渲染”:

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
    {
        protected override void OnElementChanged(ElementChangedEventArgs args)
        {
            base.OnElementChanged(args);
            if (Control == null)
            {
                UILabel label = new UILabel
                {
                    Text = "Hello from iOS!",
                    Font = UIFont.SystemFontOfSize(24)
                };
                SetNativeControl(label);
            }
        }
    }
}

这个HelloViewRenderer类必须公开,它继承自泛型类ViewRenderer。两个泛型参数中,第一个TView对应Xamarin.Forms中的类(也就是HelloView),第二个TNativeView对应iOS平台的原生控件类型。在iOS上,显示文本的标准组件是UIKit命名空间下的UILabel,这里正是选用了它。泛型参数相当于在声明:“一个HelloView对象,实际上会被渲染成一个iOS的UILabel对象”。

渲染器的核心工作在于重写OnElementChanged方法。当HelloView对象被创建时,该方法就会被调用,它的职责就是创建那个真正用于显示内容的原生控件。

OnElementChanged的实现中,首先检查Control属性是否为null。这个Control属性由ViewRenderer定义,类型就是泛型参数中的TNativeView,因此在iOS项目中它是UILabel类型。第一次调用时,Control肯定为null,此时需要创建一个新的UILabel对象,设置好文本和字体大小,然后通过SetNativeControl方法将其注册进去。此后,Control属性就指向这个已创建的UILabel

文件顶部的using指令分为三组:Xamarin.Forms命名空间用于编写ExportRenderer特性;Xamarin.Forms.Platform.iOS用于引用ViewRendererUIKit则用于使用UILabel。最后还有HelloRenderersHelloRenderers.iOS,仅仅是因为ExportRenderer特性中的两个类型引用需要它们。这种为了一个引用而专门引入一个命名空间的做法确实有些繁琐。不过有一个小技巧:你可以直接在特性中使用完全限定名,从而省去这两个using语句。

接下来看看Android版本。Android项目中的HelloViewRenderer.cs文件就采用了这种完全限定名的写法:

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
    {
        protected override void OnElementChanged(ElementChangedEventArgs args)
        {
            base.OnElementChanged(args);
            if (Control == null)
            {
                SetNativeControl(new TextView(Context)
                {
                    Text = "Hello from Android!"
                });
                Control.SetTextSize(ComplexUnitType.Sp, 24);
            }
        }
    }
}

这个渲染器同样继承自Android版本的ViewRenderer。泛型参数表明,HelloView在Android上由TextView来呈现。同样,在第一次调用OnElementChangedControlnull。这里直接创建TextView并调用SetNativeControl,一气呵成。注意TextView的构造函数需要一个Android的Context对象,该对象可以通过OnElementChanged方法的参数获取。

调用完SetNativeControl之后,Control属性就获得了实际的TextView对象。然后通过这个Control调用SetTextSize方法设置字号。在Android中,文本尺寸有多种缩放单位,ComplexUnitType.Sp代表“缩放像素”,这也是Xamarin.Forms处理Label字体大小时的兼容方式。

最后是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
    {
        protected override void OnElementChanged(ElementChangedEventArgs args)
        {
            base.OnElementChanged(args);
            if (Control == null)
            {
                SetNativeControl(new TextBlock
                {
                    Text = "Hello from the UWP!",
                    FontSize = 24,
                });
            }
        }
    }
}

在所有Windows平台上,HelloView最终由Windows.UI.Xaml.Controls命名空间中的TextBlock来渲染。Windows Phone(WinPhone)和Windows标准项目中的写法大同小异,区别只在于命名空间以及显示的文本内容。

2019_06_03_131710

运行效果如上图所示。可以看到,通过HelloView对象上设置的HorizontalOptionsVerticalOptions属性,文本被完美居中在屏幕中央。但请注意,你无法在这个HelloView上直接设置HorizontalTextAlignmentVerticalTextAlignment,因为这些属性是Label类特有的,并非View基类提供的。如果希望将HelloView升级为一个功能完善的文本视图,下一步就需要开始向HelloView类中添加自定义属性了。下一篇内容,我们将深入探讨如何实现这一目标。

来源:https://developer.aliyun.com/article/704433
上一篇MARA AI酒店评价管理软件助力提升在线声誉与满意度 下一篇Claude Code半年使用复盘:命令、搭档与两个坑
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
RAG四标融合企业知识资产体系四库协同GEO优化实践
AI教程 · 2026-07-01

RAG四标融合企业知识资产体系四库协同GEO优化实践

生成式AI正在彻底改写信息检索的底层逻辑。传统SEO依赖关键词堆砌和外链建设的策略,在大模型的内容采信规则下已经基本失效。取而代之的,是生成式引擎优化(GEO)。它不再关注外链数量,而是重点衡量你的知识是否结构化、证据链是否坚实、信源是否可靠——这些维度才是RAG(检索增强生成)架构真正看重的核心指

一个普通上班人分享WorkBuddy使用心得与真实体验
AI教程 · 2026-07-01

一个普通上班人分享WorkBuddy使用心得与真实体验

前言 最近我开始使用WorkBuddy——这是腾讯推出的一款AI办公工作台。差不多用了一周时间,趁印象还新鲜,把真实的使用感受记录下来,给还在犹豫的朋友做个参考。不吹不黑,只说实际体验。 初印象:不只是聊天机器人 之前用过不少AI工具,大多数就是个对话框,你问它答,答完就结束了。WorkBuddy不

AI幻觉变真功能实战教程:App Inventor 2视频录制拓展一周开发实录
AI教程 · 2026-07-01

AI幻觉变真功能实战教程:App Inventor 2视频录制拓展一周开发实录

先讲一个颇具戏剧性的开端。 这件事的开端颇显荒诞——有用户前来咨询,称AI Pro版的介绍中提到我们有一款“视频录制拓展”。团队全体成员都感到困惑,翻遍产品列表,发现根本不存在该组件。AI那种“一本正经胡说八道”的能力,这次确实让我们陷入尴尬。 按常理,此事到此便可结束——一句“抱歉,暂时没有这个拓

别再混淆OLAP和SQL-on-Hadoop两者查询本质不同
AI教程 · 2026-07-01

别再混淆OLAP和SQL-on-Hadoop两者查询本质不同

OLAP和SQL-on-Hadoop虽都使用SQL查询数据,但本质不同。SQL-on-Hadoop负责海量数据批量计算与ETL,查询速度秒级至分钟级;OLAP通过预聚合实现毫秒级多维分析,适合BI报表。两者在数据平台分工协作,前者是后厨加工,后者是前台快速服务。

GEO优化深度解析:AI偏好FAQ还是长文内容?
AI教程 · 2026-07-01

GEO优化深度解析:AI偏好FAQ还是长文内容?

在GEO优化中,AI对内容形式无统一偏好:FAQ在简单查询中引用率41%,长文在复杂查询中达58%。内容应基于用户意图选择形式,FAQ适配简单事实类问题,长文建立主题权威,两者互补而非替代。