zoukankan      html  css  js  c++  java
  • MAUI中构建跨平台原生控件实现

    简介

    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;
                        else
                            nativeProgressBar.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来处理不同平台控件的行为, 与控件本身解耦并且更加容器支持更多的平台。

  • 相关阅读:
    P4781 【模板】拉格朗日插值
    P1306 斐波那契公约数
    P1154 奶牛分厩
    P1028 数的计算
    P1445 [Violet]樱花
    2020 Multi-University Training Contest 4
    Codeforces Round #658 (Div. 2) D
    2020牛客暑期多校训练营(第八场) K
    Codeforces Round #659 (Div. 2)
    #10106. 「一本通 3.7 例 2」单词游戏
  • 原文地址:https://www.cnblogs.com/zh7791/p/15598496.html
Copyright © 2011-2022 走看看