简介

MAUI中使用Handler体系来处理不同平台的原生控件实现, 即对应的, 如果我们想要创建控件, 只需要创建基于不同平台的Handler即可。
那么下面主要教大家如何通过创建Handler(事件处理程序)来构建自己的控件。

开始

下面, 将通过创建一个进度条控件案例, 来演示如何在MAUI项目中创建平台控件并且使用它。
假设控件包含基础的三项功能, 进度条颜色(Foreground)、进度条当前值(Value)、进度条模式(Indeterminate)
1.第一步(声明控件类)
首先, 创建MyProgressBar类, 定义对应的依赖属性

internal class MyProgressBar : View{public static readonly BindableProperty ForegroundProperty =BindableProperty.Create(nameof(Foreground),typeof(Color),typeof(MyProgressBar),Colors.Transparent);public static readonly BindableProperty ValueProperty =BindableProperty.Create(nameof(Value),typeof(double),typeof(MyProgressBar),0.0);public static readonly BindableProperty IndeterminateProperty =BindableProperty.Create(nameof(Indeterminate),typeof(bool),typeof(MyProgressBar),false);public Color Foreground{get { return (Color)GetValue(ForegroundProperty); }set { SetValue(ForegroundProperty, value); }}public double Value{get { return (double)GetValue(ValueProperty); }set { SetValue(ValueProperty, value); }}public bool Indeterminate{get { return (bool)GetValue(IndeterminateProperty); }set { SetValue(IndeterminateProperty, value); }}}

2.第二步(创建标准处理程序)
有了控件的标准属性定义之后, 接下来就是定义标准的Handler处理程序, 其中包含控件属性映射器及构造函数, 如下所示:

partial class MyProgressBarHandler{public static PropertyMapper<MyProgressBar, MyProgressBarHandler> HorizontalProgressBarMapper = new(ViewHandler.ViewMapper){[nameof(MyProgressBar.Value)] = MapValue,[nameof(MyProgressBar.Foreground)] = MapForeground, [nameof(MyProgressBar.Indeterminate)]= MapIndeterminate};public MyProgressBarHandler(PropertyMapper mapper): base(mapper){}public MyProgressBarHandler() : base(HorizontalProgressBarMapper){}}

3.第三步(创建平台处理程序)
在属性映射器中, 我们可以很轻松看见对应了三个属性的事件处理程序, 但是目前并没有定义它, 这意味着你需要在不同平台下分别实现对应的
三个事件处理程序, 所以很快阿, 赶紧在Platforms > Android > Controls 下定义了一个MyProgressBarHandler, 如下所示:

接着继承于ViewHandler并且与原生安卓ProgressBar关联。

using Android.Widget;partial class MyProgressBarHandler :ViewHandler<MyProgressBar, ProgressBar>{ }

重写CreateNativeView(这是创建本地控件最开始的地方)

protected override ProgressBar CreateNativeView(){return new ProgressBar(Context, null,  Android.Resource.Attribute.ProgressBarStyleHorizontal){Indeterminate = true,Max = 10000,}; }

紧接着, 实现三个事件处理程序方法, MapValue、MapForeground、MapIndeterminate

static void MapValue(MyProgressBarHandler handler, MyProgressBar view){var nativeView= handler?.NativeView;nativeView.Progress = (int)(view.Value * Max);}static void MapForeground(MyProgressBarHandler handler, MyProgressBar view){UpdateForeground(handler?.NativeView, view.Foreground);static void UpdateForeground(ProgressBar nativeProgressBar, Color color){if (color == null){(nativeProgressBar.Indeterminate ? nativeProgressBar.IndeterminateDrawable :nativeProgressBar.ProgressDrawable)?.ClearColorFilter();}else{var tintList = ColorStateList.ValueOf(color.ToNative());if (nativeProgressBar.Indeterminate)nativeProgressBar.IndeterminateTintList = tintList;elsenativeProgressBar.ProgressTintList = tintList;}}}static void MapIndeterminate(MyProgressBarHandler handler, MyProgressBar view){var nativeView= handler?.NativeView;nativeView.Indeterminate = view.Indeterminate;}

4. 对应的实现iOS平台的Handler事件处理程序, 与上步骤相同, 对于事件的处理细节则对应不同平台的逻辑处理。

partial class MyProgressBarHandler :ViewHandler<MyProgressBar, UIProgressView>{protected override UIProgressView CreateNativeView()
{return new UIProgressView(UIProgressViewStyle.Default);}static void MapValue(MyProgressBarHandler handler, MyProgressBar view)
{var nativeView = handler.NativeView;nativeView.Progress = (float)view.Value;}static void MapForeground(MyProgressBarHandler handler, MyProgressBar view)
{var nativeView = handler.NativeView;nativeView.ProgressTintColor = view.Foreground?.ToNative();} static void MapIndeterminate(MyProgressBarHandler handler, MyProgressBar view)
{//...}}

5.打开MauiProgram文件, 添加AddHandler

public static MauiApp CreateMauiApp(){var builder = MauiApp.CreateBuilder();builder.UseMauiApp<App>().ConfigureFonts(fonts =>{fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");}).ConfigureMauiHandlers(handler =>{handler.AddHandler(typeof(MyProgressBar), typeof(MyProgressBarHandler));});  return builder.Build();}

6.界面中,分别声明MAUI原生控件与自定义控件

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"x:Class="MAUIRender.MainPage"xmlns:my="clr-namespace:MAUIRender" xmlns:ctor="clr-namespace:MAUIRender.Controls" BackgroundColor="{DynamicResource SecondaryColor}"><Grid><StackLayout><ProgressBar   Progress="30" ProgressColor="Red"/><ctor:MyProgressBar Indeterminate="True"Value="600"  Foreground="Green" /></StackLayout></Grid>
</ContentPage>

运行实际效果:

总结

通过利用Handler来处理不同平台控件的行为, 与控件本身解耦并且更加容器支持更多的平台。

MAUI中构建跨平台原生控件实现相关推荐

  1. ScrollView中嵌套原生控件+WebView+原生控件出现的WebView滑动顶部的冲突问题。

    开发中常有一个界面中为了灵活动态可配,常常出现在一个界面中添加WebView来加载动态URL, 界面如下所示(图中最外层为ScrollView,红色为原生控件,中间的绿色是一个WebView来动态加载 ...

  2. 跨平台图表控件TeeChart使用教程:导入XML数据

    2019独角兽企业重金招聘Python工程师标准>>> TeeChart的最新版中包含了一个自动加载XML数据的新组件.这个组件的名字叫做TTeeXMLSource,用户可以在Tee ...

  3. JS与APP原生控件交互

    "热更新"."热部署"相信对于混合式开发的童鞋一定不陌生,那么APP怎么避免每次升级都要在APP应用商店发布呢?这里就用到了混合式开发的概念,对于电商网站尤其显 ...

  4. WindowsXamlHost:在 WPF 中使用 UWP 的控件(Windows Community Toolkit)

    原文 WindowsXamlHost:在 WPF 中使用 UWP 的控件(Windows Community Toolkit) Windows Community Toolkit 再次更新到 5.0. ...

  5. Android 原生控件之三 ProgressBar

    Android 原生控件之三 ProgressBar 相关 来源 开始 不确定的进度 确定的进度 XML属性 1.android:animationResolution 2.android:indet ...

  6. Android 原生控件之一 TextView

    Android 原生控件之一 TextView 前言 来源 开始 XML属性 1.android:allowUndo 2.android:autoLink 3.android:autoSizeMaxT ...

  7. Android 原生控件之二 ImageView

    Android 原生控件之二 ImageView 相关 来源 开始 XML属性 1.android:adjustViewBounds 2.android:baseline 3.android:base ...

  8. GMap.NET入门详细教程【1】--------下载 GMap.NET,并在VS中添加GMap.NET控件

    GMap.NET入门 下载 GMap.NET,并在VS中添加GMap.NET控件 初始化并加载一张地图 添加标记点.线.多边形 为控件添加事件,在鼠标单击时打点 GMap.NET GMap.NET是开 ...

  9. Qt项目UI文件中新添加的控件在代码中不识别的问题

    ui->XXXX 在UI界面中新添加了控件,但是在代码中怎么也不出现,或者划红线 我看不少人说备份删除文件再添加,或者关闭QT再打开... 其实只要右键项目清除构建,然后重新构建就可以了, 这有 ...

最新文章

  1. 车辆匹配和平均车速计算
  2. 导入python库linux_Linux下Python安装PyMySQL成功,但无法导入的问题
  3. js 层随着滚动条上下移动
  4. 微信小程序学习日记day1
  5. lua split实现(lua程序设计10.6练习10.1题)
  6. 打印机共享无法正常打印的处理思路
  7. java随机一个数字和字母_java怎么实现随机4个带有数字和字母的验证码?
  8. asp.net跳转页面的三种方法比较
  9. 第一百六十天 how can I 坚持
  10. Cartesian k-means论文理解
  11. 天梯赛座位分布-一点都不垃圾的模拟题,代码长度超过100行的都是傻子
  12. 联想电脑Fn热键驱动
  13. 解决 psftp local: unable to open 的问题
  14. snmpwalk访问华为防火墙snmp服务超时失败问题
  15. cad卸载_CAD卸载不干净导致安装失败?别慌!老司机手把手教你卸载!
  16. springboot2.0启动报错The APR based Apache Tomcat Native library which allows optimal performance in ...
  17. 感恩节 | Hulu Thanksgiving Potluck聚餐
  18. 灰度图转热力图_热力图下看区域城市密集度,密集度较高的主要在沿海和省会周边...
  19. 推荐一款个人资料管理软件(免费,Wizknowledge)
  20. 万字带你入门Go语言(建议收藏)

热门文章

  1. void 类型的指针
  2. Juniper Firewall多进单出配制实例
  3. python3.5安装pip_win10上python3.5.2第三方库安装(运用pip)
  4. PHP 利用Mail_MimeDecode类提取邮件正文
  5. c++ why can't class template hide its implementation in cpp file?
  6. python 新闻摘要_每日新闻摘要:Microsoft内部禁止应用程序,这样就可以了
  7. chrome浏览器崩溃_不只是您:Chrome浏览器在Windows 10的2018年4月更新中崩溃
  8. 905. 按奇偶排序数组
  9. CLIENT系列、OFFSET系列、SCROLL系列
  10. shell变量/环境变量和set/env/export用法_转