MAUI Android端无法通过Handler.PlatformView设置CustomEntry样式
Android端MAUI CustomEntry样式不生效的原因及解决办法
问题描述
我创建了CustomEntry自定义Entry控件,希望实现无下划线带边框的输入框,将Xamarin Render中的代码移植到MAUI的EntryHandler中,但Android端设置BackgroundColor、CornerRadius、BorderThickness、BorderColor等样式无效。相关代码如下:
CustomEntry定义
public class CustomEntry : Entry { public static BindableProperty CornerRadiusProperty = BindableProperty.Create(nameof(CornerRadius), typeof(int), typeof(CustomEntry), 0); public static BindableProperty BorderThicknessProperty = BindableProperty.Create(nameof(BorderThickness), typeof(int), typeof(CustomEntry), 0); public static BindableProperty PaddingProperty = BindableProperty.Create(nameof(Padding), typeof(Thickness), typeof(CustomEntry), new Thickness(5)); public static BindableProperty BorderColorProperty = BindableProperty.Create(nameof(BorderColor), typeof(Color), typeof(CustomEntry), Color.FromRgba(0, 0, 0, 0)); public int CornerRadius { get => (int)GetValue(CornerRadiusProperty); set => SetValue(CornerRadiusProperty, value); } public int BorderThickness { get => (int)GetValue(BorderThicknessProperty); set => SetValue(BorderThicknessProperty, value); } public Color BorderColor { get => (Color)GetValue(BorderColorProperty); set => SetValue(BorderColorProperty, value); } /// <summary> /// This property cannot be changed at runtime in iOS. /// </summary> public Thickness Padding { get => (Thickness)GetValue(PaddingProperty); set => SetValue(PaddingProperty, value); } }
XAML布局
<?xml version="1.0" encoding="utf-8" ?> <ContentPage x:Class="MauiApp.CustomEntry.MainPage" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:controls="clr-namespace:MauiApp.CustomEntry.Controls" Shell.NavBarIsVisible="False"> <ScrollView> <VerticalStackLayout Padding="30" Spacing="25"> <controls:CustomEntry Padding="20,0,0,0" BackgroundColor="White" BorderColor="Blue" BorderThickness="2" CornerRadius="0" Placeholder="Insert a text" PlaceholderColor="Orange" Text="" /> </VerticalStackLayout> </ScrollView> </ContentPage>
MauiProgram中的Handler代码
public static class MauiProgram { public static Microsoft.Maui.Hosting.MauiApp CreateMauiApp() { var builder = Microsoft.Maui.Hosting.MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); Microsoft.Maui.Handlers.EntryHandler.Mapper .AppendToMapping("MyCustomization", (handler, view) => { #if ANDROID if (view is MauiApp.CustomEntry.Controls.CustomEntry) { var entry = (MauiApp.CustomEntry.Controls.CustomEntry)view; handler.PlatformView.SetPadding(Convert.ToInt32(entry.Padding.Left), Convert.ToInt32(entry.Padding.Top), Convert.ToInt32(entry.Padding.Right), Convert.ToInt32(entry.Padding.Bottom)); var gd = new Android.Graphics.Drawables.GradientDrawable(); gd.SetColor(entry.BackgroundColor.ToAndroid()); gd.SetCornerRadius(entry.CornerRadius + 0f); gd.SetStroke(entry.BorderThickness, entry.BorderColor.ToAndroid()); handler.PlatformView.SetBackground(gd); } #elif IOS if (view is CustomPaddingEntry) { var entry = (CustomPaddingEntry)view; handler.PlatformView.LeftView = new UIView(new CGRect(0, 0, entry.PaddingLeft, 1)); handler.PlatformView.LeftViewMode = UITextFieldViewMode.Always; handler.PlatformView.RightView = new UIView(new CGRect(0, 0, entry.PaddingRight, 1)); handler.PlatformView.RightViewMode = UITextFieldViewMode.Always; //TODO MAUI HANDLER - VERIFY IT handler.PlatformView.BorderStyle = UIKit.UITextBorderStyle.None; } #endif }); return builder.Build(); } }
原因分析
- 原生样式覆盖:Android原生EditText默认带有下划线和背景着色效果,你的自定义背景会被原生的
BackgroundTintList覆盖。 - 单位未转换:MAUI的
CornerRadius、Padding使用的是与设备无关的单位,直接赋值给Android控件会导致样式尺寸不符合预期。 - 属性变更无回调:自定义绑定属性未设置变更回调,动态修改属性时无法触发UI更新(初始化不生效主要是前两个原因)。
解决办法
修改Android端Handler代码
public static class MauiProgram { public static Microsoft.Maui.Hosting.MauiApp CreateMauiApp() { var builder = Microsoft.Maui.Hosting.MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); Microsoft.Maui.Handlers.EntryHandler.Mapper .AppendToMapping("MyCustomization", (handler, view) => { #if ANDROID if (view is MauiApp.CustomEntry.Controls.CustomEntry entry) { // 禁用原生下划线和背景着色,避免覆盖自定义样式 handler.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Android.Graphics.Color.Transparent); // 将MAUI单位转换为Android像素 var metrics = Android.Content.Res.Resources.System.DisplayMetrics; float cornerRadius = entry.CornerRadius * metrics.Density; int paddingLeft = (int)(entry.Padding.Left * metrics.Density); int paddingTop = (int)(entry.Padding.Top * metrics.Density); int paddingRight = (int)(entry.Padding.Right * metrics.Density); int paddingBottom = (int)(entry.Padding.Bottom * metrics.Density); var gd = new Android.Graphics.Drawables.GradientDrawable(); gd.SetColor(entry.BackgroundColor.ToAndroid()); gd.SetCornerRadius(cornerRadius); gd.SetStroke(entry.BorderThickness, entry.BorderColor.ToAndroid()); handler.PlatformView.SetBackground(gd); handler.PlatformView.SetPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); } #elif IOS if (view is MauiApp.CustomEntry.Controls.CustomEntry entry) { handler.PlatformView.LeftView = new UIKit.UIView(new CoreGraphics.CGRect(0, 0, entry.Padding.Left, 1)); handler.PlatformView.LeftViewMode = UIKit.UITextFieldViewMode.Always; handler.PlatformView.RightView = new UIKit.UIView(new CoreGraphics.CGRect(0, 0, entry.Padding.Right, 1)); handler.PlatformView.RightViewMode = UIKit.UITextFieldViewMode.Always; handler.PlatformView.BorderStyle = UIKit.UITextBorderStyle.None; } #endif }); return builder.Build(); } }
给CustomEntry添加属性变更回调(可选,支持动态更新)
修改自定义绑定属性的创建代码,添加属性变更回调:
public class CustomEntry : Entry { public static BindableProperty CornerRadiusProperty = BindableProperty.Create(nameof(CornerRadius), typeof(int), typeof(CustomEntry), 0, propertyChanged: OnCustomPropertyChanged); public static BindableProperty BorderThicknessProperty = BindableProperty.Create(nameof(BorderThickness), typeof(int), typeof(CustomEntry), 0, propertyChanged: OnCustomPropertyChanged); public static BindableProperty PaddingProperty = BindableProperty.Create(nameof(Padding), typeof(Thickness), typeof(CustomEntry), new Thickness(5), propertyChanged: OnCustomPropertyChanged); public static BindableProperty BorderColorProperty = BindableProperty.Create(nameof(BorderColor), typeof(Color), typeof(CustomEntry), Color.FromRgba(0,0,0,0), propertyChanged: OnCustomPropertyChanged); // ... 原有属性get/set代码不变 ... private static void OnCustomPropertyChanged(BindableObject bindable, object oldValue, object newValue) { if (bindable is CustomEntry entry && entry.Handler != null) { // 触发Handler更新所有自定义属性 entry.Handler.UpdateValue(nameof(CornerRadius)); entry.Handler.UpdateValue(nameof(BorderThickness)); entry.Handler.UpdateValue(nameof(BorderColor)); entry.Handler.UpdateValue(nameof(Padding)); } } }
内容的提问来源于stack exchange,提问作者saramgsilva
相关产品推荐
相关产品推荐

