从2015年接触Xamarin到至今已经2个年头,我对Xamarin的技能没有长进多少,但它却已经足够成熟到在跨平台移动开发工具中占有一席之地。在扫了一些资料之后,突然发现国外有很多移动端的应用已经是用Xamarin开发,Telerik还有专门的团队来开发Xamarin UI 库,这再次激发起了我的兴趣!吓得我赶紧找了个视频做了个demo, 下面就一起来体验一下用C# 开发一个Material Deisgn风格的Android应用的乐趣吧。
先来看一下我们开发出来的应用是个什么样子?一个酷炫的tab view 和 list
下面是一个左侧菜单
这是一个Collapsing Tool Bar的实现效果
最后还有一个bottom sheet
整个例子中好玩的地方非常多,我们分为UI和C#代码两块来看。因为在整个UI层几乎是和原生Android开发一模一样,所以如果原来做过Android开发又懂C#,那用Xamarin来开发安卓程序几乎是没有什么学习成本 。那么对于没有Android开发经验的C#同学来说,学习Android的UI绘制则是必不可少的部份。
UI层的开发
- Layout 与 Widget
- Material Design 和 Android Support Library
- AppbarLayout + TabLayout
- DrawerLayout + NavigationView
- CollapsingLayout + NestedView + CardView
- ListView 与 RecyclerView
C#代码完成的那些事
- 控件与事件绑定
- Activity 之间数据传递
- 多线程
Layout与Widget
Android的页面视图由XML来声明,而所有页面的这些UI组件都由一个布局(Layout)来组织。Android最早一共提供了6种基本布局。
- Linear Layout
- Relative Layout
- Table Layout
- Grid View
- Tab Layout
- List View
Widget则是一些其它的UI组件
- Date Picker
- Time Picker
- Form Elements(Button, TextView, CheckBox, RadioButton, Toggle Button, Rating Bar)
- Spinner
- Auto Complete
- Gallery
- WebView
- Tool Bar
- View Pager
- 等...
我们将会在后续的文章来详细再介绍这些Layout 和 Widgets的使用,今天我们的主角不是他们。而是Google基本Material Design 为android 开发的一套Design Support Library。
Material Design 和 Design Support Library
关于Material Deisgn已经有一份非常详细的中文文档http://design.1sters.com/,Google在2014年推出的全新的设计语言,这种设计语言旨在为手机、平板电脑、台式机和“其他平台”提供更一致、更广泛的“外观和感觉”。Google遵循MD设计风格重构了自己的几个主要APP并发布了安卓的DesignSupportLibrary来让大家更好地开发基于这种设计风格的APP。
我们的Demo中用到的组件包括:
- AppBarLayout + Tab Layout 实现 图1中的Tab视图
- Drawer Layout + Navigation View 实现图3中的左侧菜单
- CoordinatorLayout
- CollapsingToolbar Layout + NestedScrollView (图2中的页面往下滚图片缩小直到消失的效果实现 )
- Recycler View (ListView的加强版,适合数据量大的List展示)
由于后面的三个CoordinatorLayout、CollapsingToolbar以及RecyclerView相对来说会有些复杂,所有我们后面会留专门的篇幅来讲,感兴趣的同学可以自己先研究起来或者关注后面的博客~
AppBarLayout + Tab Layout
TabLayout可以说是一个非常好用的视图,你几乎在每一个主流的APP里面都可以看到。我们用Support Library实现起来就非常的方便,下面是这几个组件的结构,ViewPager与AppBarLayout同级。
这里不太想给大家展示太多关于UI层的代码,如果感兴趣的同学可以直接到我的GitHub里面去下载。我们主要看一下C#如何在ViewPager里面放视图同时与TabLayout关联起来。只需要3步:
- 找到tab和view控件
- 通过TabAdapter给ViewPager设置视图
- 将ViewPager绑定到tab
var tabs = FindViewById(Resource.Id.tabs); var viewPager = FindViewById (Resource.Id.viewpager); SetUpViewPager(viewPager); tabs.SetupWithViewPager(viewPager);
SetUpViewPager方法如下:
private void SetUpViewPager(ViewPager viewPager) { var adapter = new TabAdapter(SupportFragmentManager); adapter.AddFragment(new Fragment1(), "Fragment 1"); adapter.AddFragment(new Fragment2(), "Fragment 2"); adapter.AddFragment(new Fragment3(), "Fragment 3"); viewPager.Adapter = adapter; }
是不是很简单?
DrawerLayout + NavigationView
图3中的左侧菜单,主流APP必备,也是只要几行代码就可以了。
在NavigationView的使用上,有两个属性需要注意一下。一个左侧菜单分为两部份:headerLayout和menu。
<android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_height="match_parent" android:layout_width="325dp" android:layout_gravity="start" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_header" app:menu="@menu/drawer_view" />
所以我们需要有另外两个文件nav_header和drawer_view来配合一起完成这个菜单视图。
nav_header其实很简单用了一个
xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/nav_home" android:icon="@drawable/ic_dashboard" android:title="Home" /> <item android:id="@+id/nav_messages" android:icon="@drawable/ic_event" android:title="Messages" /> <item android:id="@+id/nav_friends" android:icon="@drawable/ic_headset" android:title="Friends" /> <item android:id="@+id/nav_discussion" android:icon="@drawable/ic_forum" android:title="Discussion" /> group> <item android:title="Sub items"> <menu> <item android:icon="@drawable/ic_dashboard" android:title="Sub item 1" /> <item android:icon="@drawable/ic_forum" android:title="Sub item 2" /> menu> item> menu>
实现一个这样的菜单只需要5分钟就搞定了~
控件与事件绑定
在VS操纵UI组件是一件非常简单的事。找到这个控件,接下来一切都变得简单,和之前的winform以及webform几乎是没有两样。
protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); var btnSelectDate = FindViewById
在上面的代码中我们找到了 btnSelectDate的代码,然后绑定了它的Click事件来打开一个选择日期的Dialog。这里的事件处理我们用的是一个匿名方法。
而在这个Dialog的OnDateSelected事件我们则绑定了一个声明方法。注:OnDateSelected这个事件是我们自己声明的,而这个声明方法,相信大家不会觉得陌生。
DatePickerFragment.cs中用委托来声明事件,当然你也可以用传递Action的方式来解决。
public delegate void DateSelectedHandle(DateTime dt); public event DateSelectedHandle OnDateSelected; public void OnDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { var selectedDate = new DateTime(year, monthOfYear + 1, dayOfMonth); if (OnDateSelected != null) { OnDateSelected(selectedDate); } }
这就是100%的C#代码。
Activity 之间数据传递
Android中Layout与Activity大家可以理解为webform中的.aspx页面与.aspx.cs code behind。 只是在Activity中我们还需要手动通过FindViewById来找到这个UI组件。如果Activity代表了一整个View,那我们来看看在不同的View之间如何传递数据。
var context = view.Context; // CheeseDetailActivity是我们要跳转过去的Activity var intent = new Intent(context, typeof(CheeseDetailActivity)); // 将数据Put到Extra中即可 EXTRA_NAME为这个数据的key intent.PutExtra(CheeseDetailActivity.EXTRA_NAME, values[position]); context.StartActivity(intent);
在CheeseDetailActivity中,只需要通过Intent.GetStringExtra(); 来获取即可
string cheeseName = Intent.GetStringExtra(EXTRA_NAME);
多线程
其实这里的多线程本不需要被提起,我只是为了向大家展示一下,这种线程处理也是100%C#来写。毕竟,越小的差异对于我们来说学习成本就越小。只是这里要注意一下,如果在非主线程中要操作UI,则需要调用RunOnUiThread(这名字起的也是好。。)
void signUpDialog_mOnSignUpComplete(object sender, OnSignUpEventArgs e) { mProgressBar.Visibility = ViewStates.Visible; Task.Run(() => { Thread.Sleep(3000); RunOnUiThread(() => { mProgressBar.Visibility = ViewStates.Invisible; }); }); }
小结
在这个盛行全干的时代,我想每个人都应该懂移动端开发。Xamarin为我们提供了一种简单、高效的方式来开发强大的、如原生般体验的APP。结合C#优雅的语法和宇宙最强大的IDE,这个事情也许值得一试。
你还可以扫描下面的二维码通过微信来看这篇文章。