Android 5.0 Lollipop曾是在android版本发布中其中一个最重要的版本,在很大程度上是引进了material design。material design是一个新的设计语言,让android developers在ui编写上更加方便。下面将会介绍如何使用material design,但google的人明白这对那些只专注后台兼容性的人是一个挑战。借助android design support library,给程序员们带来了许多重要的materials design组件,兼容android 2.1或者更高。你会使用到如下的一些组件:navigation drawer view,floating action button,floating labels for editing text,snack bar,tabs,和一个结合motion、scroll的框架将他们连接在一起。

下面的例子的代码在

git clone https://github.com/LxxCaroline/SampleApplication.git

在该工程下supportSample的模块中。


1. Navigation View

导航抽屉(navigation drawer)是一个重要的组件,它可以让你更方便的撰写app的导航菜单,navigation view中的items可以从menu资源中获取。

可以在android.support.v4.widget.DrawerLayout中使用navigation view当菜单

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:id="@+id/drawer_layout"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:fitsSystemWindows="true">    <include layout="@layout/view_content" />    <android.support.design.widget.NavigationView        android:id="@+id/navigation"        android:layout_width="250dp"        android:layout_height="match_parent"        android:layout_gravity="start"        app:headerLayout="@layout/nav_header"        app:itemTextColor="#000"        app:menu="@menu/menu_main" /></android.support.v4.widget.DrawerLayout>

需要注意几个属性:

1.app:headerLayout:该属性(可选)控制菜单的头部,也就是上图中紫色的部分

2.app:menu:该属性控制菜单栏下面的导航items,也就是上图中看到的home, message, friend, discussion。

3.app:itemTextColor:该属性控制导航items的文字颜色,还有类似的itemTextAppearance等。

最简单的菜单栏可以有以下的内容

<group android:checkableBehavior="single">    <item        android:id="@+id/navigation_item_1"        android:checked="true"        android:icon="@drawable/ic_android"        android:title="@string/navigation_item_1"/>    <item        android:id="@+id/navigation_item_2"        android:icon="@drawable/ic_android"        android:title="@string/navigation_item_2"/></group>

被选中的item将会高亮显示在菜单栏中,当然你也可以有子菜单,分隔开不同组的items

<item    android:id="@+id/navigation_subheader"    android:title="@string/navigation_subheader">    <menu>        <item            android:id="@+id/navigation_sub_item_1"            android:icon="@drawable/ic_android"            android:title="@string/navigation_sub_item_1"/>        <item            android:id="@+id/navigation_sub_item_2"            android:icon="@drawable/ic_android"            android:title="@string/navigation_sub_item_2"/>    </menu></item>

接下来是监听菜单栏items的监听事件onNavigationItemSelectedListener,监听器中会告诉你哪一个item被点击了,在点击事件中可以执行一些操作,例如改变选中的状态,加载新的页面等。


2.Floating Labels for editing text

在material design中连最普通的EditText也有改善。当该输入框还没有焦点时会正常显示hint在输入框中,当获得焦点时,hint会以动画的形式显示在输入框的上方,一致保持可见的状态,让hint成为一个floating label。

<android.support.design.widget.TextInputLayout        android:layout_width="match_parent"        android:layout_height="wrap_content">        <EditText              android:layout_width="match_parent"              android:layout_height="wrap_content"              android:hint="Username" /></android.support.design.widget.TextInputLayout>


这里需要介绍他的一些属性

android.support.design:counterEnabled="true"
android.support.design:counterTextAppearance="@style/counterText“
android.support.design:counterOverflowTextAppearance="@style/counterOverride"
android.support.design:counterMaxLength="10“
android.support.design:hintAnimationEnabled="true“
android.support.design:errorEnabled="true“ (setError(CharSequence))
android:hint=“MyCustomHint“

1.counterEnabled:textInputLayout支持对当前输入的字符进行计数,当将该开关打开,则会自动计数

2.counterTextAppearance:该属性是用于设置计数文案的appearance,可以再styles.xml中写出你想要的效果,这里我只是简单的设置了textColor

3.counterOverflowTextAppearance:这个属性需要搭配counterMaxLength混合使用,当我设置counterMaxLength为10的时候,如果当前字符超出了10,则设置当前count的文案appearance,此时hint的文案也会跟随着count变动。

4.counterMaxLength:该属性是用于设置counter的最大值

5.hintAnimationEnabled:随着焦点的移动,hint文案会动画显示,当焦点在edittext的时候,hint会自动缩小动画过渡至左上方,当焦点消失时,hint会自动变大动画过渡至Edittext内。如果将该属性设为false,则动画关闭,hint文案会较突兀的从左上方移至Edittext内。

6.errorEnabled:TextInputLayout支持错误信息,例如当获取Edittext内容为空时,可以让其显示错误信息。只用将开关打开,并在代码中调用setError("your custom error hint")即可。

7.android:hint:这个参数和Edittext类似。在TextInputLayout有个浮动的label,该label是设置提示语的,如果没有给TextInputLayout设置该属性的话,则会去Edittext中获取hint,如果Edittext中也没有的话,该label不显示。如果Edittext中有的话,则该label显示Edittext的hint。如果Edittext中有该属性,并且TextInputLayout也有该属性的话,则TextInputLayout的属性优先有效,显示在label的地方,而Edittext的hint显示在输入框内。

看下效果


另外需要注意的是,引用上述属性时(除hint外),前缀都是android.support.design,通过xmlns:android.support.design="http://schemas.android.com/apk/res-auto"

不要用xmlns:android.support.design="http://schemas.android.com/tools"

3. Floating Action Button

悬浮按钮是一个圆形的按钮,接受界面上的点击事件,这和普通的button没有什么区别,用法一致。

google提供了该button的两种大小,分别为normal和mini,,你可以通过app:fabSize=""来设置,当然你也可以通过layout_width和layout_height来设置。

该按钮继承自ImageView,所以你可以用属性src来设置显示图片。


4.SnackBar

在snack bar还没出现之前,我们都是用toast来与用户进行沟通,现在提供了一种新的交互方式---snack bar。这是一个轻量级的,并且可以用户可以通过点击的方式快速响应。snack bar显示在屏幕的底部,它包括一个显示text(主要内容)的和一个提供点击的text,在一定的时间过后,该snack bar就会消失,和toast一样。当然你也可以将它滑出界面。

Snackbar  .make(parentLayout, R.string.snackbar_text, Snackbar.LENGTH_LONG)  .setAction(R.string.snackbar_action, myOnClickListener)  .show(); // Don’t forget to show!




5. Tabs 在不同的view之间通过tabs来切换对于material design来说并不是一个新的观念,tabs可以作为顶级导航模式来组织app中不同的内容,而material design使我们能够更加简便的使用TabLayout。 在xml中的布局:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:orientation="vertical">    <android.support.design.widget.TabLayout        android:id="@+id/tab_layout"        android:layout_width="match_parent"        app:tabMode="scrollable"        app:tabSelectedTextColor="#FF00FF00"        android:layout_height="wrap_content" />    <android.support.v4.view.ViewPager        android:id="@+id/view_pager"        android:layout_width="match_parent"        android:layout_height="match_parent" /></LinearLayout>

在Activity中你可以通过如下方式来添加tab
TabLayout tabLayout = ...;tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));
而上面的方法只为tabLayout添加了tab,具体tab显示的内容还没有完成,需要用ViewPager,原来将ViewPager与TabLayout一一对应起来的代码很麻烦,当然material design提供了更加简单的方法,代码如下所示
mTabLayout = (TabLayout) findViewById(R.id.tab_layout);mViewPager = (ViewPager) findViewById(R.id.view_pager);final PagerAdapter adapter = new PagerAdapter() {    @Override    public int getCount() {        //设置总共有几个tab        return 10;    }    @Override    public boolean isViewFromObject(View view, Object object) {        return view == object;    }    @Override    public CharSequence getPageTitle(int position) {        //指定对应position的tab的名字,显示在tab上的title文字        return "tab" + position;    }    //初始化每个tab内容的页面,需要根据不同位置来加载不同的页面    @Override    public Object instantiateItem(ViewGroup container, int position) {        TextView tv = new TextView(SecondActivity.this);        tv.setText("tv" + position);        tv.setTextSize(30.f);        container.addView(tv);        return tv;    }    //必须实现该函数,否则在左右滑动的时候会抛出异常说该函数未实现    @Override    public void destroyItem(ViewGroup container, int position, Object object) {        ((ViewPager) container).removeView((View) object);    }};mViewPager.setAdapter(adapter);//将TabLayout和ViewPager连接起来mTabLayout.setupWithViewPager(mViewPager);

这里我们使用到了PagerAdapter,这个类帮我们填充ViewPager中的页面,当你要实现PagerAdapter时,你必须至少要实现以下几个方法:
  • instantiateItem(ViewGroup, int)
  • destroyItem(ViewGroup,int,Object)
  • getCount()
  • isViewFromObject(View, Object)

PagerAdapterAdapterViews所使用的适配器相比,功能会更多。AdapterViews所使用的适配器直接提供一套View的回收机制,而PagerAdapter却提供了在View更新过程中每一个步骤所对应的回调函数。PagerAdapter可以按照需要自定义View的回收机制或者使用一套更加复杂的用来管理page view的方法,比如说可以将Fragment的管理机制用于page view的管理机制当中。

ViewPager不是直接与Views关联而是与一个key对象关联起来。这个key对象用来记录并且在这个适配器中唯一地标示某个页面。而这个唯一性与页面所处的位置无关。如果ViewPager的页面内容改变,那么系统就会调用这个ViewPager所对应的PagerAdapterstartUpdate(ViewGroup)方法。之后,系统会根据页面中的内容,调用若干次instantiateItem(ViewGroup, int)或者destroyItem(ViewGroup, int, Object)方法,最后,在这次更新结束之前,系统会调用finishUpdate(ViewGroup)方法。在finishUpdate结束之前instantiateItemdestroyItem方法会分别完成将key objects所对应的view对象加载到其父ViewGroup中和删除之。而isViewFromObject(View, Object)方法可以用于判断某个view是否对应某个key对象。其中,我们可以简单地将Page Views本身作为key objects,我们可以在instantiateItem(ViewGroup, int)创建view对象和将这个对象添加到父ViewGroup中,并且最后将这个view对象作为这个方法的返回值。同样地,destroyItem(ViewGroup, int, Object)也可以类似操作。相对于地,isViewFromObject(View, Object)可以这样子实现:

return view == object;.

PagerAdapter支持数据集更新。其中,Data set改变必须要发生在主线程中,并且最后必须要调用notifyDataSetChanged()方法。这点与AdapterView adapters很相似。数据集的改变,可以实时地更新页面。假如,PagerAdapter实现了getItemPosition(Object)方法,那么ViewPager可以保持当前的页面处于状态。


6. CoordinatorLayout 富有特色的视觉只是material design中的一部分,手势也同样是重要的一部分。当然这里有许多的手势在material design,包括touch ripples(动态壁纸)和 meaningful transtions(有意义的转换).material design中提供了这样的一个coordinatorLayout,该layout在子视图之间提供了额外的一层来控制touch events(触摸事件)。 最好的例子就是当你在coordinatorLaytout中加一个floatingActionButton按钮时,为floatingActionButton添加点击事件,点击后出现snackBar,并传coordinatorLayout给snackBar为第一个参数,效果可以点击该视频看。当显示snackBar时,coordinatorLayout会自动将floatingActionButton上移,来显示SnackBar。 代码如下
CoordinatorLayout rootLayout = (CoordinatorLayout) findViewById(R.id.coordinator_layout);FloatingActionButton fabBtn = (FloatingActionButton) findViewById(R.id.fabBtn);fabBtn.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        Snackbar.make(rootLayout, "Hello. I am Snackbar!", Snackbar.LENGTH_SHORT)                .setAction("Undo", new View.OnClickListener() {                    @Override                    public void onClick(View v) {                    }                })                .show();    }});

<?xml version="1.0" encoding="utf-8"?><android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:id="@+id/coordinator_layout"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <android.support.design.widget.FloatingActionButton        android:id="@+id/fabBtn"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="bottom|right"        android:layout_marginBottom="7dp"        android:layout_marginRight="7dp"        android:src="@drawable/ic_plus"        app:borderWidth="0dp"        app:fabSize="normal" /></android.support.design.widget.CoordinatorLayout>
我们只需要写这么点代码就可以实现视频中的效果了。那些动态的效果完全由coordinatorLayout来完成。
接下来讲下CoordinatorLayout其他方面的用处,首先来看下该效果,点击这里
怎么样,这效果够炫吧,这也只需要几行xml的代码就能实现,先来看下google对scroll techniques的说明:点击这里
只要你想实现该动态滑动的效果,tool Bar和app Bar动态收拢和展开的效果前提是该页面有滑动的操作,如果该页面只是单纯显示自然不会有该效果,这点是需要读者注意的,刚开始写了个demo,发现根本没效果,那是因为我的页面只有个按钮,怎么滑,当然不会出现该效果了,我也是真是傻到家了。。。。。
还要注意的是CoordinatorLayout是一个协同的布局,如果你想要几个view协同工作的话,需要将该View放入到CoordinatorLayout中,不过事实上并没有那么方便,不是所有的View放进去都能够很好的进行协同。刚刚上述讲到只有该页面滑动才会出现视频中的效果,一听到滑动就想到了ListView和ScrollView,但是可惜的是这两个并不支持协同工作,material design中提供了另外两个类来代替,分别是android.support.v7.widget.RecyclerView和android.support.v4,widget.NestedScrollView。 下面看段代码
<?xml version="1.0" encoding="utf-8"?><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:orientation="vertical">    <!--  Your Scrollable View-->    <android.support.v7.widget.RecyclerView        android:id="@+id/lv"        android:layout_width="match_parent"        android:layout_height="match_parent"        app:layout_behavior="@string/appbar_scrolling_view_behavior" />    <android.support.design.widget.AppBarLayout        android:id="@+id/appbar_layout"        android:layout_width="match_parent"        android:layout_height="256dp"        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">        <android.support.v7.widget.Toolbar            android:id="@+id/toolbar"            android:layout_width="match_parent"            android:layout_height="56dp"            android:layout_gravity="top"            app:layout_collapseMode="pin"            app:layout_scrollFlags="scroll|enterAlways"            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"            app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />        <ImageView            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:scaleType="centerCrop"            android:src="@drawable/header"            app:layout_collapseMode="parallax"            app:layout_collapseParallaxMultiplier="0.7"            app:layout_scrollFlags="scroll|enterAlways" />    </android.support.design.widget.AppBarLayout></android.support.design.widget.CoordinatorLayout>
在MainActivity中只要填充RecyclerView的内容即可,这里不再介绍。请细看xml中的代码,最顶上的layout使用了CoordinatorLayout,AppBarLayout是用来显示滑动收缩展开的效果的工具。看里面的有些属性 app:layout_scrollFlags该属性有以下几个值
  • scroll:任何想要被滑动移除屏幕的话都要使用该属性,也就是说你想要达到视频中的效果都要添加改属性。那些没有使用该属性的view在滑动时将会被固定在屏幕的顶端。
  • enterAlways:该标志位表示当该view被滑入页面时,会先展开全部。比如说一个页面上上面显示ImageView和ToolBar,下面显示了RecyclerView,刚开始先将ImageView和ToolBar滑出页面,此时再将ImageView和ToolBar滑入,你看到的效果是先将ImageView和ToolBar拉入,这时RecyclerView才会有相应的滑动,看到其他不可见的Item。
  • enterAlwaysCollapsed:这个参数和上面那个参数的唯一区别是,当ImageView和ToolBar滑入时,不会全部显示,而是先显示预先定义的一个宽度,当你松手后,再次滑入,该ImageView和ToolBar才会完全展开。也就是说当你滑入ImageView和ToolBar,并想要完全显示的话,需要滑动两次。
  • exitUntilCollapsed:当一个view被收起完毕时,会认为该view已退出。
该段代码的效果是当RecyclerView向下滑动时,ImageView和ToolBar都会隐藏,如果你只想要ToolBar隐藏而ImageView不隐藏的话,只需要将ImageView中的layout_scrollFlags去掉即可。 这里需要注意的一点是:all views using the scroll flag must be declared before views that do not use the flag. This ensures that all views exit from the top, leaving the fixed elements behind.翻一下就是所有使用scroll属性的view必须在未使用scroll属性的view前面,这样可以确保当所有可以被滑出页面的view被滑出后,那些固定的view可以固定。 我试了下,当ToolBar无该属性,但是ImageView有属性时,Recycler的滑动并不会造成ImageView有什么效果。所以声明的时候还是要注意下顺序。 另外还有一个属性也很重要
app:layout_behavior="@string/appbar_scrolling_view_behavior"
如果你将该句代码从RecyclerView中去掉,RecyclerView会放置在AppBarLayout视图层的下面,也就是说RecyclerView被AppBarLayout挡住了,如果只有加上该句话,RecyclerView就会显示在该AppBarLayout的下面,能够完全显示出来。
给大家看下效果

那下面再讲下android.support.design.widget.CollapsingToolbarLayout,该控件可以是滑动收缩展开更加酷炫 看下xml代码
<?xml version="1.0" encoding="utf-8"?><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:orientation="vertical">    <!--  Your Scrollable View-->    <android.support.v7.widget.RecyclerView        android:id="@+id/lv"        android:layout_width="match_parent"        android:layout_height="match_parent"        app:layout_behavior="@string/appbar_scrolling_view_behavior"         />    <android.support.design.widget.AppBarLayout        android:id="@+id/appbar_layout"        android:layout_width="match_parent"        android:layout_height="256dp"        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">        <android.support.design.widget.CollapsingToolbarLayout            android:layout_width="match_parent"            android:layout_height="match_parent"            app:contentScrim="#71f"            android:id="@+id/collapsingToolbarLayout"            app:expandedTitleMarginStart="64dp"            app:layout_scrollFlags="scroll|exitUntilCollapsed">            <ImageView                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:scaleType="centerCrop"                android:src="@drawable/header"                app:layout_collapseMode="parallax"                app:layout_collapseParallaxMultiplier="0.7"                app:layout_scrollFlags="scroll|enterAlways" />            <android.support.v7.widget.Toolbar                android:id="@+id/toolbar"                android:layout_width="match_parent"                android:layout_height="56dp"                android:layout_gravity="top"                app:layout_collapseMode="pin"                app:layout_scrollFlags="scroll|enterAlways"                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"                app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />        </android.support.design.widget.CollapsingToolbarLayout>    </android.support.design.widget.AppBarLayout></android.support.design.widget.CoordinatorLayout>

需要注意下,CollapsingToolBarLayout是一个FrameLayout,该例子中需要将ToolBar声明在ImageView的后面,否则ToolBar会被遮挡。
 其他什么都没变,只是在AppBarLayout中加了个子控件,包装了ToolBar和ImageView,这样会让效果更加酷炫。       看下效果                  如果你改变ImageView和ToolBar的顺序,效果是这样的                    看到区别了么,当全部收起的时候,会显示一部分控件,CollapsingToolBarLayout会显示最后一个view的一部分。          上述的这些效果一点java代码都没写,全都在xml中完成了,对android developers是不是一个好事呢!       当然你可以可以为CollapsingToolBarLayout设置title,该title在滑动时会自动变大变小       在java代码中这么写          
CollapsingToolbarLayout collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsingToolbarLayout);collapsingToolbarLayout.setTitle("Design Library");
再讲两个参数
  • app:expandedTitleMarginStart:该参数标明当CollapsingToolbarLayout展开后,title距离左边的距离
  • app:contentScrim:该参数标明当CollapsingToolbarLayout完全收起后显示的颜色
现在我将两个参数的值分别改为0dp和#000(黑色) 看下效果


再讲一个参数,在ImageView和ToolBar中

app:layout_collapseMode:该属性有两个值,分别是parallax和pin,先将ImageView中的该属性的值改为pin,看下效果


如果将该属性的值改为parallax的话,效果如下


看出区别了么,如果设为pin,那么图片只是单单的向上拉而已,如果改为parallax的话,图片就是向上卷起,而不是呆呆的向上拉。

而为toolBar设置为pin是为了防止toolBar被滑出页面,想将toolBar固定在顶端。

再讲下视觉系数

app:layout_collapseParallaxMultiplier:该参数与刚刚说到的app:layout_collapseMode参数成对使用,而且app:layout_collapseMode的值必须为parallax才有用。该值设置的是当ImageView收起时,图片的哪一部分做为显示的的部分

举个例子,现在将app:layout_collapseParallaxMultiplier设为1,看下效果


此时图片在收缩的时候,最顶端的图片并未移动,从最下方的图片开始收缩,但上方图片一直显示

再将该值设为0.1,看下效果


在图片收缩时,最下面0.1部分的图片一直显示,上方的图片不断被消失,该值可根据读者喜好设置。

CoordinatorLayout还支持自定义view哦,但是需要实现CoordinatorLayout中的Behavior。

更多相关文章

  1. android 显示系统
  2. Android之EditText 属性汇总 +限定输入某些特殊字符
  3. Android(安卓)中activity实现全屏无标题栏透明
  4. Android(安卓)6.0新控件属性记录
  5. intent-filter的data属性详述
  6. Android中悬浮窗口的实现原理和示例代码
  7. Android小知识积累 --每天进步一点点
  8. 在不使用 android:elevation 属性的情况下设置View阴影
  9. listview属性总结

随机推荐

  1. Android开机自启动
  2. Android中的classLoader
  3. android中的自定义控件
  4. Android(安卓)ApiDemos示例解析(167):Vie
  5. (安卓权限)Android(安卓)Permissions
  6. Android读写文件二
  7. Android(安卓)JNI学习笔记——so文件动态
  8. Notes on the implementation of encrypt
  9. Android使用videoview播放res/raw下的视
  10. android.inputmethodservice.KeyboardVie