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

Xamarin Forms iOS中Picker背景色与标题色自定义及点击高亮需求

我之前也碰到过类似的问题——直接改Picker的BackgroundColor经常不生效,大概率是因为原生控件的默认样式在状态变化时(比如焦点改变、弹窗关闭)把我们设置的样式给覆盖了。下面给你两个可行的方案,其中自定义渲染器的方法最稳定,推荐优先尝试:

方案一:自定义Picker+原生渲染器(推荐)

这个方法通过创建自定义Picker控件,添加绑定属性控制选中状态,再借助原生渲染器直接操作Android/iOS的底层控件,从根源上避免样式被覆盖的问题。

步骤1:创建自定义Picker控件

先定义一个带IsSelected绑定属性的Picker,用来标记当前是否被选中:

using Xamarin.Forms;

namespace YourApp.Controls
{
    public class HighlightablePicker : Picker
    {
        public static readonly BindableProperty IsSelectedProperty =
            BindableProperty.Create(nameof(IsSelected), typeof(bool), typeof(HighlightablePicker), false);

        public bool IsSelected
        {
            get => (bool)GetValue(IsSelectedProperty);
            set => SetValue(IsSelectedProperty, value);
        }
    }
}

步骤2:Android端自定义渲染器

Android的Picker底层是Spinner,我们需要监听点击事件和IsSelected属性变化,直接修改原生控件的背景和文字颜色:

using Android.Content;
using Android.Widget;
using YourApp.Controls;
using YourApp.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(HighlightablePicker), typeof(HighlightablePickerRenderer))]
namespace YourApp.Droid.Renderers
{
    public class HighlightablePickerRenderer : PickerRenderer
    {
        private Color _defaultBgColor;
        private Color _defaultTextColor;
        private readonly Color _selectedBg = Color.LightSkyBlue;
        private readonly Color _selectedText = Color.White;

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

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

            if (Control != null)
            {
                // 保存原生默认颜色
                _defaultBgColor = Control.BackgroundTintList?.DefaultColor ?? Color.Transparent;
                _defaultTextColor = Control.TextColors.DefaultColor;

                // 监听Picker点击事件
                Control.Click += OnPickerClicked;
                // 监听IsSelected属性变化
                ((HighlightablePicker)Element).PropertyChanged += OnPickerPropertyChanged;

                // 初始化样式
                UpdatePickerStyle();
            }
        }

        private void OnPickerClicked(object sender, System.EventArgs e)
        {
            var picker = (HighlightablePicker)Element;
            picker.IsSelected = true;
            // 这里需要通知其他Picker取消选中,建议在视图模型里统一处理
        }

        private void OnPickerPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(HighlightablePicker.IsSelected))
            {
                UpdatePickerStyle();
            }
        }

        private void UpdatePickerStyle()
        {
            var picker = (HighlightablePicker)Element;
            if (picker.IsSelected)
            {
                Control.SetBackgroundColor(_selectedBg);
                Control.SetTextColor(_selectedText);
            }
            else
            {
                Control.SetBackgroundColor(_defaultBgColor);
                Control.SetTextColor(_defaultTextColor);
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (Control != null)
            {
                Control.Click -= OnPickerClicked;
                ((HighlightablePicker)Element).PropertyChanged -= OnPickerPropertyChanged;
            }
            base.Dispose(disposing);
        }
    }
}

步骤3:iOS端自定义渲染器

iOS的Picker底层是UITextField+UIPickerView,我们监听编辑开始事件(点击Picker时触发),再根据IsSelected属性修改样式:

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

[assembly: ExportRenderer(typeof(HighlightablePicker), typeof(HighlightablePickerRenderer))]
namespace YourApp.iOS.Renderers
{
    public class HighlightablePickerRenderer : PickerRenderer
    {
        private UIColor _defaultBgColor;
        private UIColor _defaultTextColor;
        private readonly UIColor _selectedBg = UIColor.FromRGB(135, 206, 250);
        private readonly UIColor _selectedText = UIColor.White;

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

            if (Control != null)
            {
                // 保存原生默认颜色
                _defaultBgColor = Control.BackgroundColor;
                _defaultTextColor = Control.TextColor;

                // 监听Picker点击(编辑开始)事件
                Control.EditingDidBegin += OnPickerEditingBegin;
                // 监听IsSelected属性变化
                ((HighlightablePicker)Element).PropertyChanged += OnPickerPropertyChanged;

                // 初始化样式
                UpdatePickerStyle();
            }
        }

        private void OnPickerEditingBegin(object sender, System.EventArgs e)
        {
            var picker = (HighlightablePicker)Element;
            picker.IsSelected = true;
            // 同样,其他Picker的取消选中逻辑放在视图模型里
        }

        private void OnPickerPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(HighlightablePicker.IsSelected))
            {
                UpdatePickerStyle();
            }
        }

        private void UpdatePickerStyle()
        {
            var picker = (HighlightablePicker)Element;
            if (picker.IsSelected)
            {
                Control.BackgroundColor = _selectedBg;
                Control.TextColor = _selectedText;
            }
            else
            {
                Control.BackgroundColor = _defaultBgColor;
                Control.TextColor = _defaultTextColor;
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (Control != null)
            {
                Control.EditingDidBegin -= OnPickerEditingBegin;
                ((HighlightablePicker)Element).PropertyChanged -= OnPickerPropertyChanged;
            }
            base.Dispose(disposing);
        }
    }
}

步骤4:视图模型中管理选中状态

为了实现“点击其他Picker时,之前的恢复默认”,需要在视图模型里维护一个选中的Picker实例,当新的Picker被选中时,取消之前的选中状态:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using YourApp.Controls;

namespace YourApp.ViewModels
{
    public class MainViewModel : INotifyPropertyChanged
    {
        private HighlightablePicker _selectedPicker;

        public HighlightablePicker Picker1 { get; set; }
        public HighlightablePicker Picker2 { get; set; }
        public HighlightablePicker Picker3 { get; set; }

        public MainViewModel()
        {
            // 初始化三个Picker
            Picker1 = new HighlightablePicker { Title = "选项组1" };
            Picker2 = new HighlightablePicker { Title = "选项组2" };
            Picker3 = new HighlightablePicker { Title = "选项组3" };

            // 监听每个Picker的IsSelected变化
            Picker1.PropertyChanged += OnPickerSelectedChanged;
            Picker2.PropertyChanged += OnPickerSelectedChanged;
            Picker3.PropertyChanged += OnPickerSelectedChanged;
        }

        private void OnPickerSelectedChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName != nameof(HighlightablePicker.IsSelected)) return;

            var currentPicker = (HighlightablePicker)sender;
            if (currentPicker.IsSelected)
            {
                // 取消之前选中的Picker状态
                _selectedPicker?.SetValue(HighlightablePicker.IsSelectedProperty, false);
                _selectedPicker = currentPicker;
            }
            else if (_selectedPicker == currentPicker)
            {
                // 取消当前选中时,清空选中标记
                _selectedPicker = null;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

步骤5:XAML中使用自定义Picker

在页面里引用自定义控件,绑定到视图模型即可:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:YourApp.Controls"
             xmlns:viewmodels="clr-namespace:YourApp.ViewModels"
             x:Class="YourApp.MainPage">
    <ContentPage.BindingContext>
        <viewmodels:MainViewModel />
    </ContentPage.BindingContext>

    <StackLayout Padding="20" Spacing="10">
        <controls:HighlightablePicker x:Name="Picker1" BindingContext="{Binding Picker1}" />
        <controls:HighlightablePicker x:Name="Picker2" BindingContext="{Binding Picker2}" />
        <controls:HighlightablePicker x:Name="Picker3" BindingContext="{Binding Picker3}" />
    </StackLayout>
</ContentPage>
方案二:使用Behavior(轻量但局限性大)

如果不想写自定义渲染器,可以用Behavior来监听Picker的焦点事件,动态修改样式。但这个方法在复杂页面里可能不够灵活,且容易被原生样式覆盖:

using System.Linq;
using Xamarin.Forms;

namespace YourApp.Behaviors
{
    public class PickerHighlightBehavior : Behavior<Picker>
    {
        private Color _defaultBg;
        private Color _defaultText;

        public Color HighlightBgColor { get; set; } = Color.LightSkyBlue;
        public Color HighlightTextColor { get; set; } = Color.White;

        protected override void OnAttachedTo(Picker bindable)
        {
            base.OnAttachedTo(bindable);
            _defaultBg = bindable.BackgroundColor;
            _defaultText = bindable.TextColor;

            bindable.Focused += OnPickerFocused;
            bindable.Unfocused += OnPickerUnfocused;
        }

        private void OnPickerFocused(object sender, FocusEventArgs e)
        {
            var currentPicker = (Picker)sender;
            // 取消页面中其他Picker的高亮状态
            var page = currentPicker.Parent as ContentPage;
            if (page != null)
            {
                foreach (var picker in page.Content.Descendants().OfType<Picker>())
                {
                    if (picker != currentPicker)
                    {
                        var behavior = picker.Behaviors.OfType<PickerHighlightBehavior>().FirstOrDefault();
                        if (behavior != null)
                        {
                            picker.BackgroundColor = behavior._defaultBg;
                            picker.TextColor = behavior._defaultText;
                        }
                    }
                }
            }
            // 设置当前Picker高亮
            currentPicker.BackgroundColor = HighlightBgColor;
            currentPicker.TextColor = HighlightTextColor;
        }

        private void OnPickerUnfocused(object sender, FocusEventArgs e)
        {
            var picker = (Picker)sender;
            picker.BackgroundColor = _defaultBg;
            picker.TextColor = _defaultText;
        }

        protected override void OnDetachingFrom(Picker bindable)
        {
            base.OnDetachingFrom(bindable);
            bindable.Focused -= OnPickerFocused;
            bindable.Unfocused -= OnPickerUnfocused;
        }
    }
}

XAML使用方式:

<Picker Title="选项组" Margin="0,10,0,0">
    <Picker.Behaviors>
        <behaviors:PickerHighlightBehavior HighlightBgColor="LightSkyBlue" HighlightTextColor="White" />
    </Picker.Behaviors>
</Picker>
总结

自定义渲染器的方案最稳定,因为直接操作原生控件,不会被Xamarin.Forms的样式逻辑干扰;Behavior方案更轻量,但在页面元素复杂时,遍历控件的方式效率不高,且可能出现样式不生效的情况。根据你的需求,推荐优先使用方案一。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:46:12