查看原文
其他

如何做技术分享 | Material Design 在 Android 中的应用

2018-05-03 下位子 鸿洋

本文作者


作者:下位子

链接:

https://www.jianshu.com/p/1f3761aa1a30

本文由作者授权发布。


1前言


我刚来这个公司的时候,每个周三都会有分享会,主题自定,分享对象尽量是面向大众,一开始觉得不错,但是到后面发现分享的内容不是那么有营养,而且积极性不是很高,都是当做任务进行分享。 程序员因为较为腼腆,分享的人较少,大部分都是客户部、分析部或者推广部的分享,久而久之,氛围就比较消极。


为了提高咱们程序员发言的积极性,增添技术部的沟通氛围,决定之前的分享形式不变,但是改为月末一次,技术部的分享每周一次。主题可以是当前部门的相关技术,当然最好是能够让大众听懂。分享时能够积极讨论,最终目的提高自身的软实力,咱们程序员不能只知道敲代码,是吧?


那么,轮到我分享了,其实一个月之前就已经通知我让我准备分享,因为公司有个交易项目要上线,比较繁忙,就没太抽出时间准备,直到上个星期五才抽出周末的时间准备。


准备


说完那么多废话,开始进入正题。最终决定分享主题为『Material Design In Android』。因为之前毕设项目趣闻中有用到「Support Design」库中的控件,所以写起来会顺手一点。


https://github.com/xiaweizi/QNews


我分三部分准备:


  1. APP准备

  2. 文档准备

  3. Keynote准备

2APP准备


项目已经上传到GitHub上:


https://github.com/xiaweizi/AndroidMD


运行效果




效果图太大,将作者的图片裁切为两张了。


花了两个多小时做了这个APP,功能简单,主题明确。


先说说完成这个APP的事前准备:


1. 主题


主题是最近非常火的「终结者2:审判日」


2. 数据


数据是自己在本地写的json数据,很是尴尬,然后部署到七牛云上。地址是:WeaponInfo

https://www.qiniu.com/

http://owj4ejy7m.bkt.clouddn.com/weaponInfo


访问了下地址,发现数据链接返回数据以及不正确了,So,作者的demo可能无法运行了。   PS:大家也可以在http://www.wanandroid.com/tools/mockapi 这里放置静态模拟json数据,免费,易用。


3. 语言


用的语言是之前学的Kotlin。

Kotlin学习笔记

https://www.jianshu.com/p/f132e368b88d


4. 风格


整体的风格就是我这次分享的主题 Material Desing风格。


3整体内容结构的准备


在做PPT之前,先把结构搭好,并且把PPT的内容先准备好,到时候直接就可以复制到PPT中。


整体结构:


  1. 什么是 Material Design

  2. Material Desing的特点

  3. 从四个特点结合Android的应用剖析

  4. 在我的公司「口袋」项目中的应用


当然内容需要看官方的文档和其他资料加上总结才能完成,所以在此感谢一下文章的帮助:


  1. Material Design 学习笔记

    http://www.uisdc.com/comprehensive-material-design-note

  2. Material Design 官网介绍文档

  3. Material Design 中文介绍

    http://md.maxoxo.design/#

  4. Material Design in Android Developer


4PPT的准备


有了之前内容的编写,做PPT就方便一点。但是因为刚买的MAC,但又不想再装WPS套餐,于是用的是自带的keynote,所以使用上会有点生疏。不过,整个PPT制作下来对其使用也熟练了起来。


如果需要的话,可以加个QQ发给你。


1、封面



进入MD官网首页就是这张图片。


2、介绍



从MD上截取的动画作为入口,大概讲解一下MD的基础概念和特点。


3、特点



这里抽取了四个点:Material、Elevation、Color和Animation进行分析。


4、风格背景


文字采用圆角+阴影进行包裹,至于高度和圆角效果因为时间紧迫,没有按照严格规范进行设置,如果对这方面有要求可以参考官网详细的规范要求。



5、动画效果


说起动画,为了能够模仿MD的交互,也是现学现卖了一把。




其实就是背景的放大效果,再加上文字的位移效果。


总结


这应该是本人第一次技术分享,除了内容准备的还算充分,分享的过程不是很满意。本人性格偏内向,平时只默默的撸代码、玩游戏,不愿意主动和别人交流,所以不论分享之前还是期间都表现的很紧张,声音有明显的颤抖,整体节奏把握的不好,很快。


整个分享过程,感觉自己就是为了将PPT内容放完就等于完成任务似的,导致听的人迷迷糊糊的,一个点还没有放完就跳到了另一个点,致使整个分享结束,听众吸收的部分很少。在结束后,我们老大 也给了我不少建议:分享的内容不在于多,而在于听众吸收了多少,你匆匆忙忙的说完了,底下的人一脸懵逼,这就失去了分享的意义。


确实,技术分享本来的目的不就是为了让那些对分享主题不熟悉的人能有个大概的了解,能够从中收获到一些在自己领域中得到应用的技能,这就足够了。因此,在分享之前,自己要对分享的知识点有个充分的了解。在分享时能将每个知识点都有个透彻而又完整的分析,不要追求速度。实话说这次分享确实给我带了不少的收获,相信在下次分享中能够有一个满意的表现。




我--------------是--------------分--------------割--------------线




技术正片开始!


接下来开始分享这次分享的主要内容,因为MD的介绍和规范在官网上都有非常详细全面的介绍,所以我就不赘述了,建议自己先看一遍官方网站的介绍,这样你对MD的理解会更加深入一些。那我把链接再列出一下


  1. Material Design`官网介绍文档

    https://material.io/guidelines/

  2. Material Design 中文介绍

    http://md.maxoxo.design/#


当你把官网的内容大致浏览一遍,相信也对MD有个初步的了解,当然要想全部弄懂的话,还得需要消化一阵子,毕竟MD的设计规范细致入微。越读越能感受到它的妙处,假如你能严格按照它的规范进行开发项目,哪怕你不是专业的UI设计师,相信你的产品一定不会难看的。


那接下来就主要介绍一下Material Desing在Android中应用。。


跟随着15年Android 5.0的问世,谷歌设计师们还给我们带来的一系列的具有Material Design风格控件。这些控件被统一放置在support design库中,以供开发中使用。使用这些库的前提是API>=21,当然如果你想在 5.0 一下的设备这些控件的话,需要添加appcompat包进行向下兼容。



我的design版本是26.1.0,上图大概就是design提供的API,这里我只做简单的使用介绍,如果想了解其原理的话,可以看一下官方的介绍。


这么多我该从何说起呢?我想了下,就按照我做这个小项目,需要的控件顺序说起吧,这样也相当于大家跟我一起做出一个具有Material Design风格的APP了。


1、主题


一个项目的开始,你得先确定这个项目的主题颜色是什么?你可以使用谷歌给你提供的Material Theme:


  • @android:style/Theme.Material(深色版本)

  • @android:style/Theme.Material.Light(浅色版本)

  • @android:style/Theme.Material.Light.DarkActionBar


当然,也可以使用自定义的主题,先看一下非常普遍的图片:



可以通过定制不同的类别的主题颜色,来达到预期的主题效果。


  • colorPrimary 项目主颜色,一般是Titlebar的背景颜色

  • colorPrimaryDark 比主颜色深一点颜色,一般是状态栏颜色

  • textColorPrimary 文字的主颜色

  • windowBackground 窗口背景颜色

  • navigationBarColor 导航栏颜色


通过在styles中配置颜色来定制您的主题,并在AndroidManifest中应用。

2、BottomNavigationView


主题构建好了,下面就是主要内容架构,我大致分为四个模块:武器简介、人物简介、配件简介和空头简介。那么底下就需要一个tab进行切换,BottomNavigationView便开始登场。从名字就可以看出 「底部导航view」,主要的作用在于给每个模块一个导航定位的功能。

先看一下效果:



1. 在menu/下创建菜单文件:


<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <item
            android:id="@+id/bottom_weapon_inc"
            android:icon="@drawable/about"
            android:title="@string/weapon_inc" />

        <!--  省略部分代码     -->
    </group>
</menu>


2.XML中进行引用


<android.support.design.widget.BottomNavigationView
    android:id="@+id/navigation"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:itemBackground="@color/colorPrimary"
    app:itemIconTint="@android:color/white"
    app:itemTextColor="@android:color/white"
    app:menu="@menu/bottom_menu"/>


3. 代码中设置点击事件


navigation!!.setOnNavigationItemSelectedListener {}


3、DrawerLayout、NavigationView


和BottomNavigationView相对的,不得不介绍一下NavigationView,这两者都是导航View,后者一般需要配合DrawerLayout实现侧滑菜单效果。


请看效果:



在XML直接引用

<android.support.v4.widget.DrawerLayout
   android:id="@+id/dl_main"
   android:layout_width="match_parent"
   android:layout_weight="1"
   android:layout_height="0dp">

   <!-- 主内容 -->
   <FrameLayout
       android:fitsSystemWindows="true"
       android:id="@+id/fl_content"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

   </FrameLayout>
   <!-- 侧滑菜单内容 -->
   <android.support.design.widget.NavigationView
       android:id="@+id/nv_left"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:layout_gravity="start"
       app:headerLayout="@layout/nav_header"
       app:menu="@menu/nav_menu"/>

</android.support.v4.widget.DrawerLayout>


通过配置layout_gravity的属性来设置侧滑的方向:start:从左侧划出,end从右侧划出。


headerLayout: 设置其头布局 menu: 设置菜单布局


详细使用请看我之前写的一篇博客:高大上的DrawerLayout

https://www.jianshu.com/p/ce8a7a20c03c


4、Toolbar


整体的架构搭建好了,剩下就是开始每个模块的内容了,内容当然少不了标题,那么就开始介绍一下Toolbar。


Toolbar作为早期Android中ActionBar的替代品,定制性和操作性挺高了不少。使用的时候需要设置NoActionBar的主题。


<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"></style>


5、RecyclerView+SwipeRefreshLayout


项目中列表肯定是少不了的,那么这就不得不提RecyclerView了,强大之处不用多说,感兴趣的话看一下我之前写的博客,对其使用有个简单的介绍:简单粗暴RecyclerView

https://www.jianshu.com/p/60819de9eb42


那如果想实现侧滑删除和长按拖拽的功能怎么办呢?RecyclerView原生就支持这些,只需要继承ItemTouchHelper.Callback的类,并实现它几个抽象方法即可。


1. 创建实现ItemTouchHelper.Callback的类

internal inner class ItemTouchHelperCallback : ItemTouchHelper.Callback() {
    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
        val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
        val swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END
        return makeMovementFlags(dragFlags, swipeFlags)
    }
    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
        myAdapter!!.onItemMove(viewHolder.adapterPosition, target.adapterPosition)
        return false
    }
    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        myAdapter!!.onItemDismiss(viewHolder.adapterPosition)
    }
}


2. 和RecyclerView建立连接

val mItemTouchHelper = ItemTouchHelper(ItemTouchHelperCallback())
mItemTouchHelper.attachToRecyclerView(mRecyclerView)


实现效果如下:



6、CardView


列表结构写好了,里面内容得优化吧,CardView自带圆角和阴影效果,让每个Item看起来就非常的自然,正如其名像卡片一样,也符合了Material Design特点。


作为ViewGroup包裹子View实现圆角和阴影的效果:

<android.support.v7.widget.CardView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_margin="2dp"
   app:cardCornerRadius="5dp"
   app:cardElevation="5dp">

</android.support.v7.widget.CardView>


主要由两个属性控制:

  • cardCornerRadius:圆角半径

  • cardElevation:高度(直接影响阴影的大小)


7、CoordinatorLayout+AppBarLayout+Toolbar


列表写好了,接下来就是滑动的交互,CoordinatorLayout:作为根View或者是一个活多个子View特定的容器,用于协调子View之间滑动的交互,可以说CoordinatorLayout是整个Design库中最核心的控件。


AppBarLayout其实就是LinearLayout,通过layout_scrollFlags来控制滑动的效果。前提是滑动view必须实现NestedScrollingChild的接口,且需要配置behavior,最基本的使用就是:

<android.support.design.widget.CoordinatorLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   android:layout_width="match_parent"
   android:layout_height="match_parent">

   <android.support.design.widget.AppBarLayout
       android:id="@+id/appbar"
       android:layout_width="match_parent"
       android:layout_height="wrap_content">

       <android.support.v7.widget.Toolbar
           android:id="@+id/toolbar"
           android:layout_width="match_parent"
           android:layout_height="?attr/actionBarSize"
           android:background="?attr/colorPrimary"
           android:fitsSystemWindows="true"
           android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
           app:layout_scrollFlags="scroll|enterAlwaysCollapsed"
           app:popupTheme="@style/Theme.AppCompat.Light" />

   </android.support.design.widget.AppBarLayout>
   <android.support.v4.widget.SwipeRefreshLayout
       android:id="@+id/refresh_layout"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       app:layout_behavior="@string/appbar_scrolling_view_behavior">

       <android.support.v7.widget.RecyclerView
           android:id="@+id/recyclerView"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:foregroundGravity="center" />

   </android.support.v4.widget.SwipeRefreshLayout>
</android.support.design.widget.CoordinatorLayout>


有两个重点:


  • 滑动的view必须实现NestedScrollingChild接口。比如RecyclerView、NestedScrollView.

  • 必须配置behavior。app:layout_behavior="@string/appbar_scrolling_view_behavior"


来看一下layout_scrollFlags有哪些属性,为了方便理解,将可以滑动的view简称为ScrollView,设置了layout_scrollFlags称为DependentView:


1. scroll


子view必须设置该属性其他的属性的才会生效,这个是最基本的属性。


2. scroll|enterAlways


只要ScrollView滑动,滑动事件就会交给设置DependentView,当DependentView滑动结束才会将事件交给ScorllView。也就是下面的效果:



3. scroll|enterAlwaysCollapsed


当ScrollView向下滑动时,DependentView先折叠到最小高度(这里是0),然后将事件交给ScrollView,当ScrollView滑动结束,DependentView才继续滑动事件,直至展开,如下图所示:



4. scroll|enterAlwaysCollapsed|enterAlways


这边就展示一下折叠的效果,我们先设置最小的高度


<android.support.v7.widget.Toolbar
   android:layout_width="match_parent"
   android:layout_height="100dp"
   android:minHeight="50dp"
   app:layout_scrollFlags="scroll|enterAlwaysCollapsed|enterAlways" />


展示一下效果:



5. scroll|exitUntilCollapsed


这个搭配重点在于上拉的时候,DependentView会先折叠到最小高度,然后事件全部交给ScrollView。那下拉的时候就是当ScrollView滑动结束,才开始DependentView的滑动事件。



6. scroll|enterAlways|snap


这个snap就是在上面的基础上多了一个回弹的效果,当DependentView正在滑动,此时手指离开屏幕时,DependentView会自动移动到离自己较劲的终点或者始点。效果如下:



上面的属性完全可以像第四种情况叠加使用,至于效果自己尝试了了才能感觉到它的奥妙之处。


8、转场动画


交互有了,现在看是添加点击跳转效果了。咱们之前跳转动画都是在startActivity之后调用overridePendingTransition方法,传入进入和退出的动画实现跳转动画。Android 5.0提供了强大的转场动画,给每个item赋予了生命,跳转时,仿佛每块布局都参与了这次搬迁大运动。


使用时,需在setContentView()之前加上

window.requestFeature(Window.FEATURE_CONTENT_TRANSITIONS)


跳转时候这样写:


startActivity(intent,
   ActivityOptions.makeSceneTransitionAnimation(activity).toBundle())


跳转的界面设置转场动画或者出场动画:


window.enterTransition = Explode()
window.exitTransition = Slide()


为了看出效果我设置了2s的延迟:



9、Toast、SnackBar和AlertDialog


基本的界面写完了,剩下的就是一些逻辑上的操作啦,比如「提示」。那么Android提示分为三种:


  • 友好的Toast(比如网络失败)

  • 拥有附加行为的提示SnackBar(比如误删信息回撤)

  • 强制让用户做出选择的AlertDialg(比如未登录)


那么这三种的效果是什么呢?




大概先讲这些,有时间再进行后续补充。


严格按照Material Design风格进行开发,相信一定能开发出非常漂亮的APP!


我的博客

http://xiaweizi.cn/


推荐阅读

大厂App 性能分析与优化方案研究

如何高效的阅读技术文章



如果你想要跟大家分享你的文章,欢迎投稿~

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存