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

如何在Xamarin.Forms中创建附图所示的Picker组件

嘿,针对你想用Xamarin.Forms打造自定义样式Picker的需求,我给你整理了两种实用的实现思路,从快速封装到深度定制都覆盖到了,你可以根据自己的需求来选:

方法一:用ContentView封装通用自定义Picker(无需平台特定代码)

这种方法适合快速实现带自定义外观的Picker(比如圆角边框、自定义下拉箭头),不用写平台专属代码,跨平台通用。

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

我们用一个Grid布局包裹只读Entry(显示选中值)、Image(下拉箭头)和隐藏的原生Picker(负责触发选择逻辑),代码如下:

<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="YourApp.Controls.CustomStyledPicker">
    <Grid x:Name="PickerWrapper" 
          Padding="12" 
          BorderColor="#E0E0E0" 
          BorderWidth="1" 
          CornerRadius="8"
          BackgroundColor="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <!-- 显示选中值的只读输入框 -->
        <Entry x:Name="DisplayEntry" 
               IsReadOnly="True" 
               BackgroundColor="Transparent"
               Text="{Binding SelectedItemDisplay, Mode=OneWay}"
               Grid.Column="0"/>

        <!-- 自定义下拉箭头图标 -->
        <Image Source="dropdown_arrow" 
               WidthRequest="20" 
               HeightRequest="20"
               Margin="0 0 8 0"
               VerticalOptions="Center"
               Grid.Column="1"/>

        <!-- 隐藏的原生Picker,处理选择逻辑 -->
        <Picker x:Name="InternalPicker" 
                ItemsSource="{Binding ItemsSource}"
                SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
                ItemDisplayBinding="{Binding DisplayText}" <!-- 如果绑定复杂对象,指定显示属性 -->
                IsVisible="False"/>
    </Grid>
</ContentView>

步骤2:编写后台绑定逻辑

给ContentView添加可绑定属性,方便在页面中使用,同时添加点击事件触发Picker的选择弹窗:

public partial class CustomStyledPicker : ContentView
{
    // 定义可绑定属性:选项列表
    public static readonly BindableProperty ItemsSourceProperty =
        BindableProperty.Create(nameof(ItemsSource), typeof(IEnumerable), typeof(CustomStyledPicker), null);

    // 定义可绑定属性:选中项
    public static readonly BindableProperty SelectedItemProperty =
        BindableProperty.Create(nameof(SelectedItem), typeof(object), typeof(CustomStyledPicker), null, BindingMode.TwoWay,
            propertyChanged: OnSelectedItemChanged);

    // 定义可绑定属性:选中项显示文本
    public static readonly BindableProperty SelectedItemDisplayProperty =
        BindableProperty.Create(nameof(SelectedItemDisplay), typeof(string), typeof(CustomStyledPicker), string.Empty);

    public IEnumerable ItemsSource
    {
        get => (IEnumerable)GetValue(ItemsSourceProperty);
        set => SetValue(ItemsSourceProperty, value);
    }

    public object SelectedItem
    {
        get => GetValue(SelectedItemProperty);
        set => SetValue(SelectedItemProperty, value);
    }

    public string SelectedItemDisplay
    {
        get => (string)GetValue(SelectedItemDisplayProperty);
        set => SetValue(SelectedItemDisplayProperty, value);
    }

    public CustomStyledPicker()
    {
        InitializeComponent();
        // 点击整个控件时触发Picker弹窗
        PickerWrapper.GestureRecognizers.Add(new TapGestureRecognizer
        {
            Command = new Command(() => InternalPicker.Focus())
        });
        // 同步Picker选中值到显示文本
        InternalPicker.SelectedIndexChanged += (s, e) =>
        {
            UpdateSelectedDisplay();
        };
    }

    private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is CustomStyledPicker picker)
        {
            picker.UpdateSelectedDisplay();
        }
    }

    private void UpdateSelectedDisplay()
    {
        // 如果是复杂对象,替换成你需要显示的属性,比如 (SelectedItem as YourModel)?.Name
        SelectedItemDisplay = SelectedItem?.ToString() ?? string.Empty;
    }
}

步骤3:在页面中使用自定义Picker

在XAML中引用你的自定义控件,绑定数据源和选中项即可:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:YourApp.Controls"
             x:Class="YourApp.Views.HomePage">
    <StackLayout Padding="20" Spacing="15">
        <controls:CustomStyledPicker 
            ItemsSource="{Binding YourItemList}"
            SelectedItem="{Binding SelectedItem}"/>
    </StackLayout>
</ContentPage>
方法二:自定义渲染器(深度定制平台原生样式)

如果需要更贴近原生平台的样式定制(比如修改下拉弹窗的UI、调整原生控件的细节),可以用自定义渲染器针对Android和iOS分别处理。

Android平台渲染器

创建一个继承自PickerRenderer的类,修改原生Spinner的样式:

[assembly: ExportRenderer(typeof(Picker), typeof(CustomPickerRenderer))]
namespace YourApp.Droid.Renderers
{
    public class CustomPickerRenderer : PickerRenderer
    {
        public CustomPickerRenderer(Context context) : base(context)
        {
        }

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

            if (Control != null)
            {
                // 设置自定义背景(圆角、边框)
                Control.Background = Context.GetDrawable(Resource.Drawable.picker_custom_bg);
                // 设置文本样式
                Control.SetTextColor(Android.Graphics.Color.ParseColor("#333333"));
                Control.SetTextSize(Android.Util.ComplexUnitType.Sp, 16);
                // 添加自定义下拉箭头
                var arrowDrawable = Context.GetDrawable(Resource.Drawable.dropdown_arrow);
                arrowDrawable.SetBounds(0, 0, 40, 40);
                Control.SetCompoundDrawablesRelative(null, null, arrowDrawable, null);
                Control.CompoundDrawablePadding = 12;
            }
        }
    }
}

然后在Android的Resources/drawable目录下创建picker_custom_bg.xml文件,定义背景样式:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <solid android:color="#FFFFFF"/>
    <stroke android:width="1dp" android:color="#E0E0E0"/>
    <corners android:radius="8dp"/>
    <padding android:left="16dp" android:right="16dp" android:top="12dp" android:bottom="12dp"/>
</shape>

iOS平台渲染器

创建继承自PickerRenderer的类,修改原生UITextField(Picker在iOS上基于UITextField实现)的样式:

[assembly: ExportRenderer(typeof(Picker), typeof(CustomPickerRenderer))]
namespace YourApp.iOS.Renderers
{
    public class CustomPickerRenderer : PickerRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                // 设置圆角和边框
                Control.Layer.CornerRadius = 8;
                Control.Layer.BorderWidth = 1;
                Control.Layer.BorderColor = UIColor.FromRGB(224,224,224).CGColor;
                Control.Layer.MasksToBounds = true;
                // 设置内边距
                Control.ContentEdgeInsets = new UIEdgeInsets(12, 16, 12, 40);
                // 添加自定义下拉箭头
                var arrowImage = UIImage.FromFile("dropdown_arrow");
                Control.RightView = new UIImageView(arrowImage)
                {
                    Frame = new CGRect(0, 0, 20, 20),
                    ContentMode = UIViewContentMode.ScaleAspectFit
                };
                Control.RightViewMode = UITextFieldViewMode.Always;
                // 设置文本样式
                Control.TextColor = UIColor.FromRGB(51,51,51);
                Control.Font = UIFont.SystemFontOfSize(16);
            }
        }
    }
}

注意事项

  • 图标资源要放在对应平台的资源目录:Android放在Resources/drawable,iOS放在Resources并设置Build Action为BundleResource
  • 如果绑定的是复杂对象,记得在Picker的ItemDisplayBinding属性中指定要显示的对象属性。
  • 若要修改下拉弹窗的样式,iOS可以通过修改UIPickerView的外观,Android可以自定义Spinner的下拉布局。

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

火山引擎 最新活动