You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在.NET MAUI中实现输入时不隐藏占位文本的无边框Entry Handler

.NET MAUI实现输入时浮动占位文本的Entry Handler

我之前也碰到过一模一样的需求——要做一个无边框输入框,输入内容时占位文本(比如你说的「Last Name*」)不会直接消失,而是像Material Design那样浮到输入框上方。MAUI里确实没法直接用Xamarin的MaterialEntryRenderer了,得通过自定义Entry Handler来适配原生控件实现这个效果,下面是完整的解决方案:

第一步:定义自定义Entry类

先创建一个继承自Entry的自定义控件,添加几个可绑定属性来控制浮动标签的样式,方便在XAML里配置:

public class FloatingLabelEntry : Entry
{
    // 浮动标签的颜色
    public static readonly BindableProperty FloatingLabelColorProperty =
        BindableProperty.Create(nameof(FloatingLabelColor), typeof(Color), typeof(FloatingLabelEntry), Color.Gray);

    // 浮动标签的字体大小
    public static readonly BindableProperty FloatingLabelFontSizeProperty =
        BindableProperty.Create(nameof(FloatingLabelFontSize), typeof(double), typeof(FloatingLabelEntry), 12.0);

    public Color FloatingLabelColor
    {
        get => (Color)GetValue(FloatingLabelColorProperty);
        set => SetValue(FloatingLabelColorProperty, value);
    }

    public double FloatingLabelFontSize
    {
        get => (double)GetValue(FloatingLabelFontSizeProperty);
        set => SetValue(FloatingLabelFontSizeProperty, value);
    }
}

第二步:注册并实现自定义Handler

App.xaml.cs里给这个自定义Entry注册Handler,分Android和iOS平台分别处理:

public App(AppShell page)
{
    InitializeComponent();

    Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping(nameof(FloatingLabelEntry), (handler, view) =>
    {
        if (view is FloatingLabelEntry floatingEntry)
        {
#if __ANDROID__
            // Android端用原生的TextInputLayout实现浮动标签(Material Design原生支持)
            var textInputLayout = new AndroidX.AppCompat.Widget.TextInputLayout(handler.PlatformView.Context);
            var editText = handler.PlatformView as Android.Widget.EditText;
            
            // 把原EditText从父容器移到TextInputLayout里
            var parent = editText.Parent as Android.Views.ViewGroup;
            if (parent != null)
            {
                parent.RemoveView(editText);
                textInputLayout.AddView(editText);
                parent.AddView(textInputLayout);
            }
            
            // 配置TextInputLayout样式:设置占位文本、标签颜色、去掉边框和背景
            textInputLayout.Hint = floatingEntry.Placeholder;
            textInputLayout.SetHintTextColor(Android.Graphics.Color.ParseColor(floatingEntry.FloatingLabelColor.ToHex()));
            textInputLayout.SetBoxBackgroundColor(Android.Graphics.Color.Transparent);
            textInputLayout.BoxStrokeWidth = 0;
            
            // 保持EditText背景透明
            editText.SetBackgroundColor(Android.Graphics.Color.Transparent);
#elif __IOS__
            // iOS端手动实现浮动标签(原生无对应控件,需要自己做动画)
            var textField = handler.PlatformView as UIKit.UITextField;
            textField.BorderStyle = UIKit.UITextBorderStyle.None;
            textField.BackgroundColor = UIKit.UIColor.Clear;
            
            // 创建浮动标签控件
            var floatingLabel = new UIKit.UILabel
            {
                Text = floatingEntry.Placeholder,
                TextColor = floatingEntry.FloatingLabelColor.ToUIColor(),
                Font = UIKit.UIFont.SystemFontOfSize((nfloat)floatingEntry.FloatingLabelFontSize),
                Hidden = string.IsNullOrEmpty(textField.Text)
            };
            
            // 把标签添加到输入框的父视图
            textField.Superview.AddSubview(floatingLabel);
            
            // 设置标签的布局约束(定位到输入框左上角上方)
            floatingLabel.TranslatesAutoresizingMaskIntoConstraints = false;
            NSLayoutConstraint.ActivateConstraints(new[]
            {
                floatingLabel.LeadingAnchor.ConstraintEqualTo(textField.LeadingAnchor),
                floatingLabel.TopAnchor.ConstraintEqualTo(textField.TopAnchor, -15),
                floatingLabel.TrailingAnchor.ConstraintEqualTo(textField.TrailingAnchor)
            });
            
            // 监听输入框的编辑事件,控制标签的显示/隐藏和动画
            textField.EditingChanged += (s, e) =>
            {
                if (!string.IsNullOrEmpty(textField.Text))
                {
                    if (floatingLabel.Hidden)
                    {
                        floatingLabel.Hidden = false;
                        // 添加缩放动画,让标签平滑缩小上浮
                        UIKit.UIView.Animate(0.2, () =>
                        {
                            floatingLabel.Transform = CoreGraphics.CGAffineTransform.MakeScale(0.8f, 0.8f);
                        });
                    }
                }
                else
                {
                    if (!floatingLabel.Hidden)
                    {
                        // 反向动画,恢复标签大小后隐藏
                        UIKit.UIView.Animate(0.2, () =>
                        {
                            floatingLabel.Transform = CoreGraphics.CGAffineTransform.MakeScale(1.0f, 1.0f);
                        }, () =>
                        {
                            floatingLabel.Hidden = true;
                        });
                    }
                }
            };
            
            // 初始状态如果输入框已有文本,直接显示浮动标签
            if (!string.IsNullOrEmpty(textField.Text))
            {
                floatingLabel.Hidden = false;
                floatingLabel.Transform = CoreGraphics.CGAffineTransform.MakeScale(0.8f, 0.8f);
            }
#endif
        }
    });
}

第三步:在XAML中使用自定义Entry

现在就可以在你的页面XAML里使用这个FloatingLabelEntry了,配置好占位文本、标签样式即可:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:YourAppNamespace"
             x:Class="YourAppNamespace.YourPage">
    <StackLayout Padding="20">
        <local:FloatingLabelEntry Placeholder="Last Name*" 
                                  FloatingLabelColor="#666666"
                                  FloatingLabelFontSize="12"
                                  BackgroundColor="Transparent"
                                  TextColor="Black"
                                  Margin="0 10"/>
    </StackLayout>
</ContentPage>

关键点说明

  • Android端:利用了Material Design的TextInputLayout,它原生支持浮动标签效果,不需要自己写动画,只需要把EditText嵌套进去即可,同时通过配置去掉边框和背景,保持无边框样式。
  • iOS端:因为原生没有对应的浮动标签控件,所以手动添加了一个UILabel作为标签,通过监听输入事件控制标签的显示/隐藏,并添加了平滑的缩放动画,模拟Material Design的效果。
  • 自定义的FloatingLabelColorFloatingLabelFontSize属性让你可以灵活调整标签样式,适配你的UI设计。

内容的提问来源于stack exchange,提问作者Mars

火山引擎 最新活动