Xamarin Forms自定义Picker点击背景后无法再次打开问题求助
解决自定义Picker点击背景后无法再次打开的问题
这个问题是因为Android默认允许点击Picker弹窗的外部区域来关闭它,但关闭后Picker的内部状态没有正确重置,导致后续点击无法触发弹窗。要实现必须点击确定/取消按钮才能关闭Picker的需求,我们可以通过修改Android端的自定义Renderer来解决:
修改Android端的CustomPickerRenderer代码
我们需要重写CreatePickerDialog方法,自定义弹窗的行为,禁止点击外部关闭,同时保留原有的Picker功能:
using Android.Content; using Android.Graphics; using Android.Graphics.Drawables; using Android.App; using AppXamarin; using AppXamarin.Droid; using Xamarin.Forms; using Xamarin.Forms.Platform.Android; [assembly: ExportRenderer(typeof(CustomPicker), typeof(CustomPickerRenderer))] namespace AppXamarin.Droid { public class CustomPickerRenderer : PickerRenderer { CustomPicker element; public CustomPickerRenderer(Context context) : base(context) { AutoPackage = false; } protected override void OnElementChanged(ElementChangedEventArgs<Picker> e) { base.OnElementChanged(e); element = (CustomPicker)this.Element; if (Control != null && this.Element != null && !string.IsNullOrEmpty(element.Image)) { Control.Background = AddPickerStyles(element.Image); } } public LayerDrawable AddPickerStyles(string imagePath) { ShapeDrawable border = new ShapeDrawable(); border.Paint.Color = Android.Graphics.Color.Gray; border.SetPadding(10, 10, 10, 10); border.Paint.SetStyle(Paint.Style.Stroke); Drawable[] layers = { border, GetDrawable(imagePath) }; LayerDrawable layerDrawable = new LayerDrawable(layers); layerDrawable.SetLayerInset(0, 0, 0, 0, 0); return layerDrawable; } private BitmapDrawable GetDrawable(string imagePath) { var drawable = Resources.GetDrawable(imagePath); var bitmap = ((BitmapDrawable)drawable).Bitmap; var result = new BitmapDrawable(Resources, Bitmap.CreateScaledBitmap(bitmap, 70, 70, true)); result.Gravity = Android.Views.GravityFlags.CenterVertical; return result; } // 重写弹窗创建方法,禁止点击外部关闭 protected override Dialog CreatePickerDialog() { var picker = Element; var dialog = new AlertDialog.Builder(Context) .SetTitle(picker.Title ?? "") .SetNegativeButton(global::Android.Resource.String.Cancel, (s, a) => { // 取消时重置Picker焦点状态 Control.ClearFocus(); }) .SetPositiveButton(global::Android.Resource.String.Ok, (s, a) => { // 确认时更新选中项并重置焦点 var alertDialog = (AlertDialog)s; var numberPicker = (NumberPicker)alertDialog.ListView.Adapter.Views[0]; picker.SelectedIndex = numberPicker.Value; Control.ClearFocus(); }) .Create(); // 禁止点击外部区域或返回键关闭弹窗(若需要保留返回键关闭,可移除SetCancelable(false)) dialog.SetCancelable(false); dialog.SetCanceledOnTouchOutside(false); // 弹窗显示时初始化选中项 dialog.SetOnShowListener(new DialogShowListener(picker.SelectedIndex)); return dialog; } // 用于初始化弹窗选中项的监听类 private class DialogShowListener : Java.Lang.Object, IDialogInterfaceOnShowListener { private int _selectedIndex; public DialogShowListener(int selectedIndex) { _selectedIndex = selectedIndex; } public void OnShow(IDialogInterface dialog) { var alertDialog = (AlertDialog)dialog; var numberPicker = (NumberPicker)alertDialog.ListView.Adapter.Views[0]; numberPicker.Value = _selectedIndex; } } } }
关键修改点说明
- 锁定弹窗关闭方式:通过
SetCancelable(false)和SetCanceledOnTouchOutside(false),彻底禁止点击外部区域或返回键关闭弹窗,用户只能通过确定/取消按钮操作。 - 修复状态异常:在按钮回调中调用
Control.ClearFocus(),确保Picker的焦点状态正确重置,避免后续点击无响应的问题。 - 同步选中状态:通过
IDialogInterfaceOnShowListener在弹窗显示时,将NumberPicker的选中值与Picker的SelectedIndex同步,保持交互一致性。
这样修改后,既实现了必须通过按钮关闭Picker的需求,也解决了点击背景后无法再次打开的问题。
内容的提问来源于stack exchange,提问作者mohammad anouti
相关产品推荐
相关产品推荐

