Xamarin.Android之Spinner的简单探讨
一、前言
今天用了一下Spinner这个控件,主要是结合官网的例子来用的,不过官网的是把数据写在Strings.xml中的,
某种程度上,不是很符合我们需要的,比较多的应该都是从数据库读出来,绑定上去的。下面是官网的例子:
https://developer.xamarin.com/guides/android/user_interface/spinner/
二、来个简单的Demo
新建一个类 MyType.cs
1 public class MyType 2 { 3 public int TypeId { get; set; } 4 5 public string TypeName { get; set; } 6 7 public override string ToString() 8 { 9 return TypeId + "-" + TypeName; 10 } 11 }
再来点数据
1 public static class DB 2 { 3 public static List<MyType> Types { get; private set; } 4 5 static DB() 6 { 7 Types = new List<MyType>(); 8 Types.Add(new MyType { TypeId = 1, TypeName = "type1" }); 9 Types.Add(new MyType { TypeId = 2, TypeName = "type2" }); 10 Types.Add(new MyType { TypeId = 3, TypeName = "type3" }); 11 Types.Add(new MyType { TypeId = 4, TypeName = "type4" }); 12 } 13 }
最后写个Adapter,我们自定义的Adapter都需要继承BaseAdapter
1 public class MyTypeAdapter : BaseAdapter<MyType> 2 { 3 private readonly Activity _context; 4 private readonly IList<MyType> _types; 5 6 public MyTypeAdapter(Activity context, IList<MyType> types) 7 { 8 this._context = context; 9 this._types = types; 10 } 11 12 public override MyType this[int position] 13 { 14 get 15 { 16 return this._types[position]; 17 } 18 } 19 20 public override int Count 21 { 22 get 23 { 24 return this._types.Count; 25 } 26 } 27 28 public override long GetItemId(int position) 29 { 30 return position; 31 } 32 33 public override View GetView(int position, View convertView, ViewGroup parent) 34 { 35 View view = convertView; 36 if (view == null) 37 { 38 view = this._context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem1, null); 39 } 40 41 view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = this._types[position].ToString(); 42 return view; 43 } 44 }
到这里,会发现有好几个重写的方法!!这些方法是直接通过实现抽象类生成的,然后自己去完善每个方法。
既然都这样了,那就果断去看看这个BaseAdapter是干嘛的
1 // 2 // Summary: 3 // Common base class of common implementation for an Android.Widget.Adapter that 4 // can be /// used in both Android.Widget.ListView (by implementing the specialized 5 // /// Android.Widget.IListAdapter interface} and Android.Widget.Spinner (by implementing 6 // the /// specialized Android.Widget.ISpinnerAdapter interface. 7 // 8 // Type parameters: 9 // T: 10 // To be added. 11 // 12 // Remarks: 13 // /// 14 // Common base class of common implementation for an Android.Widget.Adapter that 15 // can be /// used in both Android.Widget.ListView (by implementing the specialized 16 // /// Android.Widget.IListAdapter interface} and Android.Widget.Spinner (by implementing 17 // the /// specialized Android.Widget.ISpinnerAdapter interface. /// 18 // /// 19 // /// /// [Android Documentation] /// /// 20 // /// 21 [DefaultMember("Item")] 22 [Register("android/widget/BaseAdapter", DoNotGenerateAcw = true)] 23 public abstract class BaseAdapter<T> : BaseAdapter 24 { 25 [Register(".ctor", "()V", "")] 26 public BaseAdapter(); 27 public BaseAdapter(IntPtr handle, JniHandleOwnership transfer); 28 29 public abstract T this[int position] { get; } 30 31 public override Java.Lang.Object GetItem(int position); 32 }
可以看到这个主要就是给ListView和Spinner用的。主要的还是它继承了BaseAdapter这个抽象类(下面的,我是去掉了注释的,方便看)
1 public abstract class BaseAdapter : Java.Lang.Object, IListAdapter, ISpinnerAdapter, IAdapter, IJavaObject, IDisposable 2 { 3 public BaseAdapter(); 4 protected BaseAdapter(IntPtr javaReference, JniHandleOwnership transfer); 5 public abstract int Count { get; } 6 public virtual bool HasStableIds { get; } 7 public virtual bool IsEmpty { get; } 8 public virtual int ViewTypeCount { get; } 9 protected override IntPtr ThresholdClass { get; } 10 protected override Type ThresholdType { get; } 11 public virtual bool AreAllItemsEnabled(); 12 public virtual View GetDropDownView(int position, View convertView, ViewGroup parent); 13 public abstract Java.Lang.Object GetItem(int position); 14 public abstract long GetItemId(int position); 15 public virtual int GetItemViewType(int position); 16 public abstract View GetView(int position, View convertView, ViewGroup parent); 17 public virtual bool IsEnabled(int position); 18 public virtual void NotifyDataSetChanged(); 19 public virtual void NotifyDataSetInvalidated(); 20 public virtual void RegisterDataSetObserver(DataSetObserver observer); 21 public virtual void UnregisterDataSetObserver(DataSetObserver observer); 22 23 public static class InterfaceConsts 24 { 25 public const int IgnoreItemViewType = -1; 26 public const int NoSelection = int.MinValue; 27 } 28 }
可以看到,我们在自定义Adapter时,自动实现的方法,有好几个是在这里面的!!!
具体每个方法是干嘛的,就看看API吧!
https://developer.xamarin.com/api/type/Android.Widget.BaseAdapter/
下面来看看我们的Activity:
1 [Activity(Label = "SpinnerActivity",MainLauncher =true)] 2 public class SpinnerActivity : Activity 3 { 4 protected override void OnCreate(Bundle savedInstanceState) 5 { 6 base.OnCreate(savedInstanceState); 7 8 // Create your application here 9 SetContentView(Resource.Layout.spinnerlayout); 10 11 var typesSpinner = FindViewById<Spinner>(Resource.Id.typesSpinner); 12 13 typesSpinner.Adapter = new Models.MyTypeAdapter(this, Models.DB.Types); 14 15 typesSpinner.ItemSelected += typesSpinner_ItemSelected; 16 } 17 18 private void typesSpinner_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e) 19 { 20 Spinner spinner = (Spinner)sender; 21 22 var toast = string.Format(spinner.GetItemAtPosition(e.Position).ToString()); 23 24 Toast.MakeText(this, toast, ToastLength.Long).Show(); 25 } 26 }
很简单,下面看看效果图
但是呢,我记得在原生的开发中,下面这句应该直接是得到一个Object对象,然后通过强制转化就可以得到对应的Model
spinner.GetItemAtPosition(e.Position)
我试过.net下面的强制转化和object获取在转化,都没办法得到想要的效果
都是这个错。
回想刚才的BaseAdapter类,它继承了Java.Lang.Object
所以就直接让我们的MyType去继承这个试试。可以点出来了!!
再来看看选择后的效果图:
OK,达到想要的效果了!!这样我们就可以得到任何我们想要的属性了!!不用只局限一个.ToString()方法了!
下面是MyType类和typesSpinner_ItemSelected方法
1 public class MyType : Java.Lang.Object 2 { 3 public int TypeId { get; set; } 4 5 public string TypeName { get; set; } 6 7 public override string ToString() 8 { 9 return TypeId + "-" + TypeName; 10 } 11 }
1 private void typesSpinner_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e) 2 { 3 Spinner spinner = (Spinner)sender; 4 5 //var toast = string.Format(spinner.GetItemAtPosition(e.Position).ToString()); 6 7 var toast = (Models.MyType)spinner.GetItemAtPosition(e.Position); 8 9 Toast.MakeText(this, toast.TypeName, ToastLength.Long).Show(); 10 }