MAUI:自定义条目

Jul*_*lot 14 maui .net-maui

我是 MAUI 新手,具有 Xamarin.Forms 的基本知识

我想向 MAUI 中的 Entry 控件添加底部边框(和边框刻度)。

在 Xamarin.Forms 上,我们必须创建一个自定义控件,然后为每个平台创建一个渲染器。

在发布此消息之前,我在互联网上进行了研究。它涉及处理程序,我的印象是它只允许基本修改(更改背景颜色等......)。

我对所有这些信息有点困惑,如果有人能启发我,我将不胜感激。

Too*_*eve 27

自定义特定控件实例显示了自定义条目的一个简单示例,该示例仅自定义每个平台的一些属性。

我已经开始创建一个.Net Maui 高级自定义条目示例。请参阅该存储库以了解迄今为止的实施情况。

地位:

  • 演示 Windows 上的下划线颜色和粗细。
  • Android 上有下划线开头。

限制(当前):

  • 在 Windows 上,有些Entry properties需要映射到包含的 TextBox。
  • 尚未测试Entry events,看看是否需要任何特殊处理。
  • Android 下划线无法控制其粗细或颜色。
  • 在 Windows 或 iOS 以外的平台上没有实现。

如果您希望进一步扩展,请搜索xamarin forms customize entry renderer特定于平台的代码示例。希望我已经展示了足够的内容来让大家了解如何/在哪里添加此类代码。


此时,做一个高级示例似乎比相应的 Xamarin Forms“自定义渲染器”需要更多工作。

理由:

  • 需要适应毛伊岛的处理程序映射方案。可能只需要高级文档和示例。
  • 由于IEntry和所需的类型,难以扩展现有的 EntryHandler IEntryHandler。如何覆盖PlatformView??的类型
  • 很难复制现有处理程序的功能(以便进行细微的更改),因为内置处理程序使用的某些扩展是“内部”的,因此必须复制这些文件。其中引用了其他文件。然后我复制了。并进行了一些更改以避免与现有扩展发生歧义冲突。

TBD:也许有一种方法可以避免我遇到的并发症。
另外,可能有我复制的代码,可以省略。


这些是需要完成的步骤:

  1. 定义MyEntry : Entry具有所需附加属性的类。
  2. 定义MyEntryHandler要呈现到本机 UI 对象的类。
  3. 在 MauiProgram 中添加处理程序。

1. 定义MyEntry : Entry具有所需附加属性的类。

在这里,我们添加UnderlineColorUnderlineThickness

public class MyEntry : Entry
{
    /// <summary>
    /// Color and Thickness of bottom border.
    /// </summary>
    public static BindableProperty UnderlineColorProperty = BindableProperty.Create(
            nameof(UnderlineColor), typeof(Color), typeof(MyEntry), Colors.Black);
    public Color UnderlineColor
    {
        get => (Color)GetValue(UnderlineColorProperty);
        set => SetValue(UnderlineColorProperty, value);
    }

    public static BindableProperty UnderlineThicknessProperty = BindableProperty.Create(
            nameof(UnderlineThickness), typeof(int), typeof(MyEntry), 0);
    public int UnderlineThickness
    {
        get => (int)GetValue(UnderlineThicknessProperty);
        set => SetValue(UnderlineThicknessProperty, value);
    }

    public MyEntry()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

2. 定义MyEntryHandler要呈现到本机 UI 对象的类。

这是通过partial class. 一部分是跨平台的,然后需要针对您实现的每个平台的另一部分。

在我的存储库中,找到MyEntryHandler.csWindows/MyEntryHandler.Windows.csAndroid/MyEntryHandler.Android.cs

MyEntryHandler.cs:

其中包含 MyEntryHandler 的“Mapper”。

    // Cross-platform partial of class. See Maui repo maui\src\Core\src\Handlers\Entry\EntryHandler.cs
    public partial class MyEntryHandler : IMyEntryHandler //: EntryHandler
    {
        // static c'tor.
        static MyEntryHandler()
        {
            // TBD: Fill MyMapper here by copying from Entry.Mapper, then add custom ones defined in MyEntry?
        }

        //public static IPropertyMapper<IEntry, IEntryHandler> MyMapper => Mapper;
        public static IPropertyMapper<IEntry, MyEntryHandler> MyMapper = new PropertyMapper<IEntry, MyEntryHandler>(ViewMapper)
        {
            // From Entry.
            [nameof(IEntry.Background)] = MapBackground,
            [nameof(IEntry.CharacterSpacing)] = MapCharacterSpacing,
            [nameof(IEntry.ClearButtonVisibility)] = MapClearButtonVisibility,
            [nameof(IEntry.Font)] = MapFont,
            [nameof(IEntry.IsPassword)] = MapIsPassword,
            [nameof(IEntry.HorizontalTextAlignment)] = MapHorizontalTextAlignment,
            [nameof(IEntry.VerticalTextAlignment)] = MapVerticalTextAlignment,
            [nameof(IEntry.IsReadOnly)] = MapIsReadOnly,
            [nameof(IEntry.IsTextPredictionEnabled)] = MapIsTextPredictionEnabled,
            [nameof(IEntry.Keyboard)] = MapKeyboard,
            [nameof(IEntry.MaxLength)] = MapMaxLength,
            [nameof(IEntry.Placeholder)] = MapPlaceholder,
            [nameof(IEntry.PlaceholderColor)] = MapPlaceholderColor,
            [nameof(IEntry.ReturnType)] = MapReturnType,
            [nameof(IEntry.Text)] = MapText,
            [nameof(IEntry.TextColor)] = MapTextColor,
            [nameof(IEntry.CursorPosition)] = MapCursorPosition,
            [nameof(IEntry.SelectionLength)] = MapSelectionLength,
            // From MyEntry
            [nameof(MyEntry.UnderlineThickness)] = MapUnderlineThickness
        };

        // TBD: What is this for? Cloned one on Entry.
        private static void MapUnderlineThickness(MyEntryHandler arg1, IEntry arg2)
        {
        }


        public MyEntryHandler() : base(MyMapper)
        {
        }
Run Code Online (Sandbox Code Playgroud)

我尚未在所有平台文件夹中创建最小部分类。在存储库的跨平台 MyEntryHandler 中,您将看到#if WINDOWS. 目的是这不需要包含在#if. 你还会看到很多被注释掉的代码;这样我就可以了解需要在每个平台上实现哪些方法。

MyEntryHandler.Windows.cs:

本质是CreatePlatformView()。在 Windows 上,我选择实现为Border包含TextBox.

        protected override PlatformView CreatePlatformView()
        {
            var myentry = VirtualView as MyEntry;

            var textbox = new MauiPasswordTextBox
            {
                // From EntryHandler.
                IsObfuscationDelayed = s_shouldBeDelayed

                // TODO: pass some entry properties through to textbox?
            };

            MauiColor color = myentry != null
                    ? myentry.UnderlineColor
                    : MyEntry.UnderlineColorProperty.DefaultValue as MauiColor;
            int thickness = myentry != null
                    ? myentry.UnderlineThickness
                    : (int)MyEntry.UnderlineThicknessProperty.DefaultValue;

            var border = new Border
            {
                Child = textbox,
                BorderBrush = color.ToPlatform(),
                BorderThickness = new Thickness(0, 0, 0, thickness)
            };


            return border;
        }
Run Code Online (Sandbox Code Playgroud)

Windows Handler 还有许多其他行。这些都是从毛伊岛来源复制的。待定需要其中哪些(如果有)。如果我知道如何简单地从 Maui 的 EntryHandler 继承,那么就不需要这些了。type但我继承时发生了冲突。


3:在MauiProgram中添加Handler。

MauiProgram.cs

    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureMauiHandlers(handlers =>
            {
                handlers.AddHandler(typeof(MyEntry), typeof(MyEntryHandler));
            })
        ...
Run Code Online (Sandbox Code Playgroud)

您将在存储库中看到添加到 Maui 项目中的其他类。这些是从毛伊岛来源复制的。

这些其他类由上面提到的类引用。

希望一旦这个主题得到更好的理解,其他大部分课程都会消失。


在 Windows 上,AppShell + MainPage 带有两个 MyEntry。一种是带下划线和彩色的。

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:myviews="clr-namespace:MauiCustomEntryHandler"
             x:Class="MauiCustomEntryHandler.MainPage">
             
    <ScrollView>
        <VerticalStackLayout 
                WidthRequest="500" HeightRequest="400"
                Spacing="25" Padding="30,0" BackgroundColor="LightBlue"
                HorizontalOptions="Center" VerticalOptions="Center">
            <Label Text="Hello, Maui!" FontSize="24" HorizontalOptions="Center" />
            <myviews:MyEntry Text="test" FontSize="20" UnderlineThickness="8"
                 UnderlineColor="Purple" BackgroundColor="HotPink" />
            <myviews:MyEntry UnderlineThickness="0" BackgroundColor="LightGray" />
        </VerticalStackLayout>
    </ScrollView>
 
</ContentPage>

Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 这是一个很好的答案。不过,请原谅我。真的没有更简单的方法吗? (2认同)
  • 很好的问题!这似乎比 Xamarin Forms 中的工作量更多。也许这就是这种高性能渲染器方法的成本 - 但我希望当更多的人尝试自定义渲染器时,如何使这变得更容易会变得更加清楚。我猜测毛伊岛需要内置更多/更好的“帮助器类”,以处理与渲染器相关的复杂性。(就我个人而言,直到 12 月或 1 月之前,我才能在 Maui 上做出重大努力。那时,我将了解如何移植我的所有 XForms 自定义渲染器。我将更深入地研究 Maui 代码,提出更好的方法。) (2认同)

Jan*_*man 6

如果有人因为(看似)简单的需要更改下划线颜色而登陆此页面,请继续阅读。下面的解决方案只需要几行代码,适用于所有使用突出显示/强调色的 MAUI 控件。

接受的回复似乎是关于如何自定义 MAUI 控件的通用描述的有价值的教程(这再次对应于可能有点通用的原始问题的标题)。然而,如果颜色行为是您唯一的目标,那就完全是矫枉过正了。

MAUI 实现基于操作系统个性化方案。不幸的是,似乎无法在所有平台的一个地方以通用方式覆盖它,但可以在特定于平台的层上控制它。

我最终得到的只是修改一个文件,即 ./Platforms/Windows/App.xaml:

    <maui:MauiWinUIApplication.Resources>
        <ResourceDictionary>
            <Color x:Key="Primary">#500073</Color>
            <StaticResource x:Key="SystemAccentColorDark1" ResourceKey="Primary"/>
            <StaticResource x:Key="SystemAccentColorDark2" ResourceKey="Primary"/>
            <StaticResource x:Key="SystemAccentColorDark3" ResourceKey="Primary"/>
            <StaticResource x:Key="SystemAccentColorLight1" ResourceKey="Primary"/>
            <StaticResource x:Key="SystemAccentColorLight2" ResourceKey="Primary"/>
            <StaticResource x:Key="SystemAccentColorLight3" ResourceKey="Primary"/>
        </ResourceDictionary>
    </maui:MauiWinUIApplication.Resources>
Run Code Online (Sandbox Code Playgroud)

这样,您的颜色将覆盖操作系统系统之一,并且据我猜测,这将修改给定平台上使用此强调色的所有控件的行为。

具有自定义下划线颜色的条目

尽管我的 Windows 设置显示蓝色作为当前的强调色:

Windows 操作系统设置颜色

最初,我尝试修改通用 ./Resources/Styles/Colors.xaml 文件,希望立即覆盖所有平台上的此行为,但这似乎不起作用。希望 MAUI 团队有一天能够实现通用行为。