是时候开始用C#快速开发移动应用了

  从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步:

  1. 找到tab和view控件
  2. 通过TabAdapter给ViewPager设置视图
  3. 将ViewPager绑定到tab
var tabs = FindViewById<TabLayout>(Resource.Id.tabs);
var viewPager = FindViewById<ViewPager>(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其实很简单用了一个<ImageView>来显示图片,以及一个<TextView>来显示上面图里面的UserName。我们可以看一下app:menu="@menu/drawer_view"的drawer_view是如何构建成菜单项的。

<?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<Button>(Resource.Id.btnDateSelector);
            // 事件绑定匿名函数
            btnSelectDate.Click += (o, e) =>
            {
                var dialog = Fragments.DatePickerFragment.NewInstance();
                dialog.OnDateSelected += Dialog_OnDateSelected; // 事件绑定另一个方法
                dialog.Show(FragmentManager, "tag");
            };
        }

        private void Dialog_OnDateSelected(DateTime dt)
        {
            var txtDate = FindViewById<TextView>(Resource.Id.txtDate);
            txtDate.Text = dt.ToLongDateString();
        }

在上面的代码中我们找到了 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,这个事情也许值得一试。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏移动开发之家

Android图片加载开源库深度推荐,安利Fresco1、Universal-Image-Loader 2、Picasso 3、Glide 4、Fresco

</p> 这里没有广告,这里没有跑分,数据对比Google一下比比皆是,额···那我说什么好(ノಠ益ಠ)ノ彡┻━┻。 对啊,女朋友···呸呸呸,那么就来讲一...

542
来自专栏Java技术

我是 SPI,我让框架更加优雅了!

自从上次小黑进入公司的架构组之后,小黑就承担起整个公司底层框架的开发工作。就在刚刚,小黑又接到一个任务:做一个通用的歌曲信息解析框架。即输入歌曲数据,之后返回该...

902
来自专栏何俊林

如何进行网络视频截图/获取视频的缩略图

小编导读:获取视频的缩略图,截图正在播放的视频某一帧,是在音视频开发中,常遇到的问题。本文是主要用于点播中截图视频,同时还可以获取点播视频的缩略图进行显示,留下...

5307
来自专栏吴小龙同學

Android 接入微信支付宝支付

按照惯例,首先通读一遍官网文档。 微信支付 前期准备 微信开放平台 注册账号,创建应用,开通微信支付,这些大家都会的。 微信商户平台 APP支付文档 https...

3969
来自专栏技术小黑屋

利用WebView实现网页的i18n

软件如果想在全球获得更多的用户,国际化与本地化(internationalization and localization 简称:i18n 和L10n)是非常必...

582
来自专栏不二小段

【一起学Python】爬取网易云歌词

说在前面:这是公众号第一篇来自小伙伴的投稿。我之前挖过一个坑,说想抓取歌词以后做文本分析,后面不了了之了。刚好Ricky作为爬虫的初学者,需要小项目练手,他就把...

35210
来自专栏developerHaoz 的安卓之旅

手把手教你从零开始做一个好看的 APP

俗话说,万事开头难,在开始敲代码之前,先让我们来做一些必要的准备,这样才能事半功倍嘛!

873
来自专栏JarvanMo的IT专栏

基于ExoPlayer的ExoVideoView

本人之前写过一篇名为基于ExoPlayer的ExoPlayerVideoView的文章,近日发现竟然被盗用了。

1092
来自专栏非著名程序员

Android 实现视屏播放器、边播边缓存功能、外加铲屎(IJKPlayer)

Android 实现视屏播放器与边播边缓存功能外加蹲坑铲屎(IJKPlayer) hello,大家好,我就是那个会掀桌子的话唠,刚刚结束两篇关于音频播放与录制的...

5229
来自专栏我就是马云飞

Architecture Components 生命周期

前言 最近这几天一直在研究官方的MVVM的实现,使用起来其实难度并不大,并且如果结合DataBinding和Dagger2 代码写的都要飞起来了,不要太好。不过...

1895

扫码关注云+社区