Xamarin-无牌器的自定义选择器

发布于 2025-01-26 09:42:03 字数 4089 浏览 2 评论 0原文

我在Xamarin项目中有一个自定义选择器,这需要我很长时间才能实现自己想要的东西。

我希望我的自定义点像这样显示

我不想要一个取消按钮,我已经实现了这一点,但是我无法找到一种

  • 没有取消按钮
  • 拾取器视图的方法,就像第一张图片

一样类

public class CustomPicker : Picker
    {
        public static readonly BindableProperty DonebuttonTextProperty = BindableProperty.Create("DonebuttonText", typeof(string),
            typeof(string), null);
        public string CancelButtonText
        {
            get { return (string)GetValue(DonebuttonTextProperty); }
            set { SetValue(DonebuttonTextProperty, value); }
        }
    }

我的在Android上进行自定义Pickerrenderer


    public class CustomPickerRenderer : Xamarin.Forms.Platform.Android.AppCompat.PickerRenderer
    {
        public CustomPickerRenderer(Context context) : base(context) { }

        private IElementController ElementController => Element as IElementController;
        private AlertDialog _dialog;

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

            if (e.NewElement == null || e.OldElement != null)
                return;

            Control.Click += Control_Click;

        }
        protected override void Dispose(bool disposing)
        {
            Control.Click -= Control_Click;
            base.Dispose(disposing);
        }

        private void Control_Click(object sender, EventArgs e)
        {
            Picker model = Element;

            var picker = new NumberPicker(Context);
            if (model.Items != null && model.Items.Any())
            {
                picker.MaxValue = model.Items.Count - 1;
                picker.MinValue = 0;
                picker.SetDisplayedValues(model.Items.ToArray());
                picker.WrapSelectorWheel = false;
                picker.DescendantFocusability = DescendantFocusability.BlockDescendants;
                picker.Value = model.SelectedIndex;
            }

            var layout = new LinearLayout(Context) { Orientation = Orientation.Vertical };
            layout.AddView(picker);

            ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, true);

            var builder = new AlertDialog.Builder(Context);
            builder.SetView(layout);
            builder.SetTitle(model.Title ?? "");
            builder.SetPositiveButton("Done", (s, a) =>
            {
                ElementController.SetValueFromRenderer(Picker.SelectedIndexProperty, picker.Value);
                // It is possible for the Content of the Page to be changed on SelectedIndexChanged.
                // In this case, the Element & Control will no longer exist.
                if (Element != null)
                {
                    if (model.Items.Count > 0 && Element.SelectedIndex >= 0)
                        Control.Text = model.Items[Element.SelectedIndex];
                    ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
                    // It is also possible for the Content of the Page to be changed when Focus is changed.
                    // In this case, we'll lose our Control.
                    Control?.ClearFocus();
                }
                _dialog = null;
            });

            _dialog = builder.Create();
            _dialog.DismissEvent += (ssender, args) =>
            {
                ElementController?.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
            };
            _dialog.Show();
        }

    }

,您可以看到我使用了xamarin.forms.platform.android.appcompat.picker,以便使用我想要的视图显示,但是如果我使用numberpicker它将像第二张照片一样显示它。

请帮助我还没有看到如何做这件事的任何例子,我一直在搜索很多。谢谢。

I have a custom picker on my Xamarin Project and it is taking me a long time to achieve what I want.

I want my CustomPicker to display like this

enter image description here

Instead of this, as I can't get to center the words and it is quicker to select with the other one.

enter image description here

I don't want a cancel button and I have already achieve that but I can't figure out a way of having both

  • No cancel button
  • Picker view like the first image

This is my CustomPicker class

public class CustomPicker : Picker
    {
        public static readonly BindableProperty DonebuttonTextProperty = BindableProperty.Create("DonebuttonText", typeof(string),
            typeof(string), null);
        public string CancelButtonText
        {
            get { return (string)GetValue(DonebuttonTextProperty); }
            set { SetValue(DonebuttonTextProperty, value); }
        }
    }

My CustomPickerRenderer on Android


    public class CustomPickerRenderer : Xamarin.Forms.Platform.Android.AppCompat.PickerRenderer
    {
        public CustomPickerRenderer(Context context) : base(context) { }

        private IElementController ElementController => Element as IElementController;
        private AlertDialog _dialog;

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

            if (e.NewElement == null || e.OldElement != null)
                return;

            Control.Click += Control_Click;

        }
        protected override void Dispose(bool disposing)
        {
            Control.Click -= Control_Click;
            base.Dispose(disposing);
        }

        private void Control_Click(object sender, EventArgs e)
        {
            Picker model = Element;

            var picker = new NumberPicker(Context);
            if (model.Items != null && model.Items.Any())
            {
                picker.MaxValue = model.Items.Count - 1;
                picker.MinValue = 0;
                picker.SetDisplayedValues(model.Items.ToArray());
                picker.WrapSelectorWheel = false;
                picker.DescendantFocusability = DescendantFocusability.BlockDescendants;
                picker.Value = model.SelectedIndex;
            }

            var layout = new LinearLayout(Context) { Orientation = Orientation.Vertical };
            layout.AddView(picker);

            ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, true);

            var builder = new AlertDialog.Builder(Context);
            builder.SetView(layout);
            builder.SetTitle(model.Title ?? "");
            builder.SetPositiveButton("Done", (s, a) =>
            {
                ElementController.SetValueFromRenderer(Picker.SelectedIndexProperty, picker.Value);
                // It is possible for the Content of the Page to be changed on SelectedIndexChanged.
                // In this case, the Element & Control will no longer exist.
                if (Element != null)
                {
                    if (model.Items.Count > 0 && Element.SelectedIndex >= 0)
                        Control.Text = model.Items[Element.SelectedIndex];
                    ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
                    // It is also possible for the Content of the Page to be changed when Focus is changed.
                    // In this case, we'll lose our Control.
                    Control?.ClearFocus();
                }
                _dialog = null;
            });

            _dialog = builder.Create();
            _dialog.DismissEvent += (ssender, args) =>
            {
                ElementController?.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
            };
            _dialog.Show();
        }

    }

As you can see I used Xamarin.Forms.Platform.Android.AppCompat.Picker in order to use the view that I want to display but then if I use NumberPicker it will display it like the second photo.

Please help I haven't seen any example of how to do this and I have been searching a lot. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

哭泣的笑容 2025-02-02 09:42:03

如果您希望选择器像第一个屏幕截图一样显示。您可以重置Picker布局以将项目放在listView中。对于IEtView中项目之间的分离器,您可以设置divider ro null。

XAML:

 <Picker x:Name="picker"
Title="Select"
TitleColor="Red">
        <Picker.ItemsSource>
            <x:Array Type="{x:Type x:String}">
                <x:String>item1</x:String>
                <x:String>item2</x:String>
                <x:String>item3</x:String>
                <x:String>item4</x:String>

            </x:Array>
        </Picker.ItemsSource>
    </Picker>

自定义渲染器:

[assembly: ExportRenderer(typeof(Picker), typeof(CustomPickerRenderer2))]
namespace App1.Droid
{
public class CustomPickerRenderer2 : PickerRenderer
{
    AlertDialog listDialog;
    string[] items;
    public CustomPickerRenderer2(Context context) : base(context)
    {

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



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

    }

    private void Control_Click(object sender, EventArgs e)
    {
        Picker model = Element;
        items = model.Items.ToArray();
        AlertDialog.Builder builder = new AlertDialog.Builder(this.Context);
        builder.SetTitle(model.Title ?? "");
        builder.SetNegativeButton("Cancel", (s, a) =>
        {
            Control?.ClearFocus();
            builder = null;
        });

        Android.Views.View view = LayoutInflater.From(this.Context).Inflate(Resource.Layout.listview, null);
        Android.Widget.ListView listView = view.FindViewById<Android.Widget.ListView>(Resource.Id.listView1);

        MyAdapter myAdapter = new MyAdapter(items, Element.SelectedIndex);
        listView.Adapter = myAdapter;
        listView.ItemClick += ListView_ItemClick;
        builder.SetView(view);
        listDialog = builder.Create();

        listDialog.Show();

    }

    private void ListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
    {
        Control.Text = items[e.Position];
        Element.SelectedIndex = e.Position;
        Console.WriteLine(items[e.Position]);
        listDialog.Dismiss();
        listDialog = null;
    }
}

class MyAdapter : BaseAdapter
{
    private string[] items;
    private int selectedIndex;

    public MyAdapter(string[] items)
    {
        this.items = items;
    }

    public MyAdapter(string[] items, int selectedIndex) : this(items)
    {
        this.selectedIndex = selectedIndex;
    }

    public override int Count => items.Length;

    public override Java.Lang.Object GetItem(int position)
    {
        return items[position];
    }

    public override long GetItemId(int position)
    {
        return position;
    }

    public override Android.Views.View GetView(int position, Android.Views.View convertView, ViewGroup parent)
    {
        if (convertView == null)
        {
            convertView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.listview_item, null);
        }
        TextView textView = convertView.FindViewById<TextView>(Resource.Id.textView1);
        textView.Text = items[position];
        return convertView;
    }
}
}

listView.xml :您可以在Android项目中在Resources/Layout中创建。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
     <ListView
   android:id="@+id/listView1"           
  android:divider="@null"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"/> 


</LinearLayout>

listView_item.xml :您可以在Android项目中在Resources/Layout中创建。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   <TextView
      android:id="@+id/textView1"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"/>
</LinearLayout>

If you want the picker to show like the first screenshot. You could reset the picker layout to put the items in a listview. For the separator between items in ietview, you could set the divider ro null.

Xaml:

 <Picker x:Name="picker"
Title="Select"
TitleColor="Red">
        <Picker.ItemsSource>
            <x:Array Type="{x:Type x:String}">
                <x:String>item1</x:String>
                <x:String>item2</x:String>
                <x:String>item3</x:String>
                <x:String>item4</x:String>

            </x:Array>
        </Picker.ItemsSource>
    </Picker>

Custom Renderer:

[assembly: ExportRenderer(typeof(Picker), typeof(CustomPickerRenderer2))]
namespace App1.Droid
{
public class CustomPickerRenderer2 : PickerRenderer
{
    AlertDialog listDialog;
    string[] items;
    public CustomPickerRenderer2(Context context) : base(context)
    {

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



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

    }

    private void Control_Click(object sender, EventArgs e)
    {
        Picker model = Element;
        items = model.Items.ToArray();
        AlertDialog.Builder builder = new AlertDialog.Builder(this.Context);
        builder.SetTitle(model.Title ?? "");
        builder.SetNegativeButton("Cancel", (s, a) =>
        {
            Control?.ClearFocus();
            builder = null;
        });

        Android.Views.View view = LayoutInflater.From(this.Context).Inflate(Resource.Layout.listview, null);
        Android.Widget.ListView listView = view.FindViewById<Android.Widget.ListView>(Resource.Id.listView1);

        MyAdapter myAdapter = new MyAdapter(items, Element.SelectedIndex);
        listView.Adapter = myAdapter;
        listView.ItemClick += ListView_ItemClick;
        builder.SetView(view);
        listDialog = builder.Create();

        listDialog.Show();

    }

    private void ListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
    {
        Control.Text = items[e.Position];
        Element.SelectedIndex = e.Position;
        Console.WriteLine(items[e.Position]);
        listDialog.Dismiss();
        listDialog = null;
    }
}

class MyAdapter : BaseAdapter
{
    private string[] items;
    private int selectedIndex;

    public MyAdapter(string[] items)
    {
        this.items = items;
    }

    public MyAdapter(string[] items, int selectedIndex) : this(items)
    {
        this.selectedIndex = selectedIndex;
    }

    public override int Count => items.Length;

    public override Java.Lang.Object GetItem(int position)
    {
        return items[position];
    }

    public override long GetItemId(int position)
    {
        return position;
    }

    public override Android.Views.View GetView(int position, Android.Views.View convertView, ViewGroup parent)
    {
        if (convertView == null)
        {
            convertView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.listview_item, null);
        }
        TextView textView = convertView.FindViewById<TextView>(Resource.Id.textView1);
        textView.Text = items[position];
        return convertView;
    }
}
}

listview.xml: You could creat in your Resources/layout in android project.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
     <ListView
   android:id="@+id/listView1"           
  android:divider="@null"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"/> 


</LinearLayout>

listview_item.xml : You could creat in your Resources/layout in android project.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   <TextView
      android:id="@+id/textView1"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"/>
</LinearLayout>

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文