You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET MAUI如何捕获退格键并在Entry控件间切换

跨平台PIN码输入框退格键焦点切换实现方案

针对你用4个Entry控件实现PIN码输入的场景,以下是Android和iOS平台捕获退格键并切换焦点的具体实现:

Android平台实现

通过自定义Entry渲染器,监听EditText的键盘事件,捕获退格键并处理焦点切换:

  1. 定义自定义PinEntry控件
using Xamarin.Forms;

namespace YourApp.Controls
{
    public class PinEntry : Entry
    {
        public static readonly BindableProperty IndexProperty = 
            BindableProperty.Create(nameof(Index), typeof(int), typeof(PinEntry), 0);
        
        public int Index 
        { 
            get => (int)GetValue(IndexProperty); 
            set => SetValue(IndexProperty, value); 
        }
    }
}
  1. 实现Android自定义渲染器
using Android.Content;
using Android.Views;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using YourApp.Controls;
using YourApp.Droid.Renderers;

[assembly: ExportRenderer(typeof(PinEntry), typeof(PinEntryAndroidRenderer))]
namespace YourApp.Droid.Renderers
{
    public class PinEntryAndroidRenderer : EntryRenderer
    {
        public PinEntryAndroidRenderer(Context context) : base(context) { }

        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);

            if (Control != null && e.NewElement is PinEntry pinEntry)
            {
                Control.SetOnKeyListener(new PinKeyListener(pinEntry));
            }
        }

        private class PinKeyListener : Java.Lang.Object, View.IOnKeyListener
        {
            private readonly PinEntry _pinEntry;

            public PinKeyListener(PinEntry pinEntry) => _pinEntry = pinEntry;

            public bool OnKey(View v, Keycode keyCode, KeyEvent e)
            {
                // 仅处理退格键按下且当前输入框为空的情况
                if (keyCode == Keycode.Del && e.Action == KeyEventActions.Down && string.IsNullOrEmpty(_pinEntry.Text))
                {
                    var page = _pinEntry.Parent as ContentPage;
                    var pinEntries = page?.Content.Descendants<PinEntry>().OrderBy(p => p.Index).ToList();
                    var currentIndex = pinEntries?.IndexOf(_pinEntry) ?? 0;

                    if (currentIndex > 0)
                    {
                        pinEntries[currentIndex - 1].Focus();
                        return true; // 消费事件,阻止默认行为
                    }
                }
                return false;
            }
        }
    }
}

iOS平台实现

通过自定义Entry渲染器,利用UITextFieldDelegate捕获退格操作,处理焦点切换:

  1. 使用同一PinEntry控件(复用Android端定义的控件)

  2. 实现iOS自定义渲染器

using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using YourApp.Controls;
using YourApp.iOS.Renderers;

[assembly: ExportRenderer(typeof(PinEntry), typeof(PinEntryIOSRenderer))]
namespace YourApp.iOS.Renderers
{
    public class PinEntryIOSRenderer : EntryRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);

            if (Control != null && e.NewElement is PinEntry pinEntry)
            {
                Control.Delegate = new PinTextFieldDelegate(pinEntry);
            }
        }

        private class PinTextFieldDelegate : UITextFieldDelegate
        {
            private readonly PinEntry _pinEntry;

            public PinTextFieldDelegate(PinEntry pinEntry) => _pinEntry = pinEntry;

            public override bool ShouldChangeCharacters(UITextField textField, NSRange range, string replacementString)
            {
                // 判断是否为退格操作:删除长度>0且替换字符串为空
                if (range.Length > 0 && string.IsNullOrEmpty(replacementString))
                {
                    // 当前输入框为空时,切换到上一个输入框
                    if (string.IsNullOrEmpty(textField.Text))
                    {
                        var page = _pinEntry.Parent as ContentPage;
                        var pinEntries = page?.Content.Descendants<PinEntry>().OrderBy(p => p.Index).ToList();
                        var currentIndex = pinEntries?.IndexOf(_pinEntry) ?? 0;

                        if (currentIndex > 0)
                        {
                            pinEntries[currentIndex - 1].Focus();
                            return false; // 消费事件
                        }
                    }
                }
                return base.ShouldChangeCharacters(textField, range, replacementString);
            }
        }
    }
}

使用方式

在XAML中添加PinEntry控件并设置索引:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:YourApp.Controls"
             x:Class="YourApp.Views.PinPage">
    <StackLayout Orientation="Horizontal" HorizontalOptions="Center" Spacing="15">
        <local:PinEntry Index="0" WidthRequest="60" HeightRequest="60" 
                        Keyboard="Numeric" MaxLength="1" HorizontalTextAlignment="Center"/>
        <local:PinEntry Index="1" WidthRequest="60" HeightRequest="60" 
                        Keyboard="Numeric" MaxLength="1" HorizontalTextAlignment="Center"/>
        <local:PinEntry Index="2" WidthRequest="60" HeightRequest="60" 
                        Keyboard="Numeric" MaxLength="1" HorizontalTextAlignment="Center"/>
        <local:PinEntry Index="3" WidthRequest="60" HeightRequest="60" 
                        Keyboard="Numeric" MaxLength="1" HorizontalTextAlignment="Center"/>
    </StackLayout>
</ContentPage>

注意事项

  • 确保项目已引用Xamarin.Forms(或Microsoft.Maui.Controls,若使用MAUI)的相关命名空间
  • 若使用MAUI,只需将渲染器的基类替换为MAUI对应的EntryRenderer,命名空间调整为Microsoft.Maui.Controls.Compatibility.Platform.Android/Microsoft.Maui.Controls.Compatibility.Platform.iOS

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 19:07:10