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

.NET MAUI Picker在Android 7.1上选中项后点击别处反复弹出

.NET MAUI Picker在Android 7.1上选中后点击外部反复弹出的解决方案

问题场景

使用.NET MAUI Picker时,在Android 7.1系统上出现异常:选中选项后点击屏幕其他区域,Picker弹窗会反复弹出;但在最新版本Android系统上运行正常。相关XAML代码如下:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             Shell.NavBarIsVisible="false"
             x:Class="Views.Picker">
    <ContentPage.Content >
        <VerticalStackLayout Margin="25, 15">
            <Label Text="Device Picker" HorizontalTextAlignment="Center"/>

            <Grid>
                <Picker Grid.Column="0" SelectedItem="Dev" Margin="0,15,0,15" WidthRequest="200" HeightRequest="40">
                    <Picker.Items>
                        <x:String>Dev</x:String>
                        <x:String>Testing</x:String>
                        <x:String>Training</x:String>
                        <x:String>Production</x:String>
                    </Picker.Items>
                </Picker>

                <Image Source="small_down_arrow.png" 
                       Grid.Column="1"
                       x:Name="devicePicker"
                       WidthRequest="15" 
                       HeightRequest="15" 
                       HorizontalOptions="End"
                       Margin="0,0,6,0"
                   >
                </Image>
            </Grid>
        </VerticalStackLayout>
    </ContentPage.Content>
</ContentPage>

问题现象:
问题现象动图

可行解决方案

方案一:自定义Android平台Picker渲染器

通过重写Android平台的Picker渲染逻辑,替换原生弹窗实现,避免低版本系统的兼容性问题。

  1. 在共享项目中定义自定义Picker控件:
namespace YourAppName.Controls
{
    public class CustomPicker : Picker
    {
    }
}
  1. 在Android项目中添加自定义渲染器:
using Android.App;
using Android.Content;
using Android.Widget;
using YourAppName.Controls;
using YourAppName.Platforms.Android.Renderers;
using Microsoft.Maui.Controls.Platform;
using Microsoft.Maui.Controls.Platform.Android;
using Microsoft.Maui.Platform;

[assembly: ExportRenderer(typeof(CustomPicker), typeof(CustomPickerRenderer))]
namespace YourAppName.Platforms.Android.Renderers
{
    public class CustomPickerRenderer : PickerRenderer
    {
        private AlertDialog _dialog;

        public CustomPickerRenderer(Context context) : base(context)
        {
        }

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

            if (Control != null && e.NewElement != null)
            {
                Control.Click += Control_Click;
            }
        }

        private void Control_Click(object sender, EventArgs e)
        {
            var picker = Element as CustomPicker;
            if (picker == null) return;

            var adapter = new ArrayAdapter(Context, Android.Resource.Layout.SimpleSpinnerDropDownItem, picker.Items);

            var dialog = new AlertDialog.Builder(Context)
                .SetTitle(picker.Title ?? "")
                .SetAdapter(adapter, (s, args) =>
                {
                    picker.SelectedIndex = args.Which;
                    _dialog?.Dismiss();
                })
                .SetNegativeButton("取消", (s, args) =>
                {
                    _dialog?.Dismiss();
                })
                .Create();

            _dialog = dialog;
            dialog.Show();
        }

        protected override void Dispose(bool disposing)
        {
            if (Control != null)
            {
                Control.Click -= Control_Click;
            }
            _dialog?.Dispose();
            base.Dispose(disposing);
        }
    }
}
  1. 在XAML中替换原Picker为自定义控件:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:YourAppName.Controls"
             Shell.NavBarIsVisible="false"
             x:Class="Views.Picker">
    <ContentPage.Content >
        <VerticalStackLayout Margin="25, 15">
            <Label Text="Device Picker" HorizontalTextAlignment="Center"/>

            <Grid>
                <controls:CustomPicker Grid.Column="0" SelectedItem="Dev" Margin="0,15,0,15" WidthRequest="200" HeightRequest="40">
                    <controls:CustomPicker.Items>
                        <x:String>Dev</x:String>
                        <x:String>Testing</x:String>
                        <x:String>Training</x:String>
                        <x:String>Production</x:String>
                    </controls:CustomPicker.Items>
                </controls:CustomPicker>

                <Image Source="small_down_arrow.png" 
                       Grid.Column="1"
                       WidthRequest="15" 
                       HeightRequest="15" 
                       HorizontalOptions="End"
                       Margin="0,0,6,0"
                   >
                </Image>
            </Grid>
        </VerticalStackLayout>
    </ContentPage.Content>
</ContentPage>

方案二:使用MAUI Popup替代原生Picker弹窗

借助CommunityToolkit.Maui的Popup组件,实现完全自定义的下拉选择界面,彻底规避原生Picker的兼容性问题,同时支持更多UI定制。

  1. 安装CommunityToolkit.Maui NuGet包。

  2. 创建Popup页面:

<?xml version="1.0" encoding="utf-8" ?>
<toolkit:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:Class="YourAppName.Views.PickerPopup"
             Size="200, 300">
    <VerticalStackLayout>
        <Label Text="选择环境" Margin="10"/>
        <CollectionView x:Name="ItemsCollection" Margin="5" SelectionMode="Single">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <Label Text="{Binding}" Padding="10" FontSize="16"/>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
        <Button Text="确定" Clicked="OnConfirmClicked" Margin="10"/>
    </VerticalStackLayout>
</toolkit:Popup>
  1. Popup页面后台代码:
using CommunityToolkit.Maui.Views;
using Microsoft.Maui.Controls;

namespace YourAppName.Views
{
    public partial class PickerPopup : Popup
    {
        public string SelectedItem { get; private set; }

        public PickerPopup(List<string> items, string currentSelected)
        {
            InitializeComponent();
            ItemsCollection.ItemsSource = items;
            ItemsCollection.SelectedItem = currentSelected;
        }

        private void OnConfirmClicked(object sender, EventArgs e)
        {
            SelectedItem = ItemsCollection.SelectedItem as string;
            Close(SelectedItem);
        }
    }
}
  1. 修改原页面,用Button触发Popup:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:Class="Views.Picker"
             Shell.NavBarIsVisible="false">
    <ContentPage.Content >
        <VerticalStackLayout Margin="25, 15">
            <Label Text="Device Picker" HorizontalTextAlignment="Center"/>

            <Grid>
                <Button x:Name="PickerButton" Text="{Binding SelectedEnv}" Margin="0,15,0,15" WidthRequest="200" HeightRequest="40" Clicked="PickerButton_Clicked"/>

                <Image Source="small_down_arrow.png" 
                       Grid.Column="1"
                       WidthRequest="15" 
                       HeightRequest="15" 
                       HorizontalOptions="End"
                       Margin="0,0,6,0"
                       InputTransparent="True"
                   >
                </Image>
            </Grid>
        </VerticalStackLayout>
    </ContentPage.Content>
</ContentPage>
  1. 原页面后台代码:
using CommunityToolkit.Maui.Views;
using Microsoft.Maui.Controls;

namespace YourAppName.Views
{
    public partial class Picker : ContentPage
    {
        public string SelectedEnv { get; set; } = "Dev";
        private readonly List<string> _envItems = new List<string> { "Dev", "Testing", "Training", "Production" };

        public Picker()
        {
            InitializeComponent();
            BindingContext = this;
        }

        private async void PickerButton_Clicked(object sender, EventArgs e)
        {
            var popup = new PickerPopup(_envItems, SelectedEnv);
            var result = await this.ShowPopupAsync(popup);
            if (result is string selected)
            {
                SelectedEnv = selected;
                OnPropertyChanged(nameof(SelectedEnv));
            }
        }
    }
}

方案选择建议

  • 若希望保留原生Picker的样式和交互逻辑,优先选择自定义渲染器方案。
  • 若需要自定义下拉界面样式,或对交互逻辑有更多控制需求,推荐使用Popup替代方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 00:08:12