GitOPEN's Home.

一个Demo学会用Android兼容包新控件

Word count: 2,981 / Reading time: 14 min
2015/07/02 Share

前言

伟大的Google为Android推出了一系列的兼容包,最新的就是Design Support Library了,这里我们结合v7和v4中的几个控件,来主要学习Design Support Library中的几个新控件!一个Demo学会用它们!

效果动图GIF:

Design Support Library Demo

学习内容

通过本实例可以学习到以下内容:

  • Drawerlayout和NavigationView实现优雅的Google范儿侧边栏;
  • 新控件CoordinatorLayout、AppBarLayout、Toolbar、FloatingActionButton的用法,以及Toolbar的渐变隐藏动画效果;
  • 官方Tabs组件TabLayout和ViewPager结合实现主界面内容区域;
  • SwipeRefreshLayout和RecyclerView结合实现下拉刷新,以及RecyclerView的数据适配器RecyclerView.Adapter的用法,还有RecyclerView中item的点击事件的实现方法;
  • 卡片式CardView的用法;
  • 类似Toast的新控件Snackbar的用法。

##布局文件

在源码中学习Android,是有种身临其境的感觉的。

学习Android解释再多代码都没有用,因为解释过了还是不会用。因此,我们这里将布局文件XML源码贴出来供学习,放心,所有知识点都已经注释在源码中。

###styles.xml源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<resources>

<style name="AppTheme" parent="MyThemeBlue"></style>

<!-- 蓝色为主色调 -->
<style name="MyThemeBlue" parent="Theme.AppCompat.Light.NoActionBar">

<!--选中状态icon的颜色和字体颜色-->
<item name="colorPrimary">@color/main_blue_light</item>
<item name="colorPrimaryDark">@color/main_blue_dark</item>
<item name="colorAccent">@color/main_blue_light</item>
<!--正常状态下字体颜色和icon颜色-->
<item name="android:textColorPrimary">@color/main_white</item>

</style>
</resources>

colorPrimary、colorPrimaryDark、colorAccent、textColorPrimary的含义,请看博文《Android L+ Theme 与 Toolbar 实例》

主布局activity_my.xml源码(重点)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<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/id_drawerlayout"
android:layout_width="match_parent"
android:layout_height="match_parent">

<!-- 第一个位置 -->
<!-- 你的主界面内容,必须放置在Drawerlayout中的第一个位置
根据自己的需要来放置控件,
例如:LinearLayout布局或者RelativeLayout布局;
也可以是单个控件,
如 TextView等 -->
<include layout="@layout/content_main" />


<!-- 第二个位置 -->
<!-- 用来放Drawerlayout中的内容,
这里使用NavigationView来实现类似Google pLay中的侧滑栏效果,
必须在build.gradle中添加compile 'com.android.support:design:22.2.0';
另外,如果不需要NavigationView效果,
也可以放置一个普通布局文件就是一个普通的侧滑栏了。
-->

<!--
注意:
如果使用NavigationView(其他控件也是一样)的特有属性,需要加上命名空间:
xmlns:app="http://schemas.android.com/apk/res-auto";
另外,一定要添加android:layout_gravity="left"属性。
-->

<!--
属性解析:
app:headerLayout: NavigationView中头部的head部分的布局,是自己实现的;
app:menu: 指定Nav中的Menu布局,就是自己写Menu中的按钮,要放在res/menu/文件夹下;
app:itemTextColor: 用来设置Nav中,menu item的颜色选择器。
还有一些属性: 和itemTextColor用法一样,指定一个颜色选择器,实现不同的颜色效果。
app:itemIconTint:
app:itemBackground:
-->
<android.support.design.widget.NavigationView
android:id="@+id/id_navigationview"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:itemTextColor="@color/selector_nav_menu_textcolor"
android:layout_gravity="left" />

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

content_main.xml源码(重点)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<?xml version="1.0" encoding="utf-8"?><!--
CoordinatorLayout是这次新添加的一个增强型的FrameLayout,通过它可以实现很多东西:
例如:
1.界面向上滚动逐渐隐藏Toolbar;
2.在其中可以放置浮动的View,就像Floating Action Button。
-->
<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/id_coordinatorlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">


<!--
AppBarLayout跟它的名字一样,把容器类的组件全部作为AppBar。
将AppBarLayout放在CoordinatorLayout中,就可以实现滚动效果。
本例中,TabLayout在界面滚动时,随着Toolbar的逐渐隐藏,将占据Toolbar的位置,
达到节省屏幕空间,界面动画效果的目的。
-->
<android.support.design.widget.AppBarLayout
android:id="@+id/id_appbarlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">


<!--

属性解析:
app:theme:指定Toolbar的样式,包括ActionbarToggle和popupMenu的指示图标颜色
app:popupTheme:指定popupMenu溢出后的样式
app:title: 指定Toolbar中主Title的内容
-->

<!--
app:layout_scrollFlags的意思是:

设置的layout_scrollFlags有如下几种选项:
scroll: 所有想滚动出屏幕的view都需要设置这个flag- 没有设置这个flag的view将被固定在屏幕顶部。
enterAlways: 这个flag让任意向下的滚动都会导致该view变为可见,启用快速“返回模式”。
enterAlwaysCollapsed: 当你的视图已经设置minHeight属性又使用此标志时,你的视图只能以最小高度进入,只有当滚动视图到达顶部时才扩大到完整高度。
exitUntilCollapsed: 当视图会在滚动时,它一直滚动到设置的minHeight时完全隐藏。

需要注意的是,后面两种模式基本只有在CollapsingToolbarLayout才有用,
而前面两种模式基本是需要一起使用的,也就是说,这些flag的使用场景,基本已经固定了。
-->
<android.support.v7.widget.Toolbar
android:id="@+id/id_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.ActionBar"
app:title="@string/toolbar_title" />

<!--
Tabs选项卡,和ViewPager搭配使用可以增大界面的内容展示量,实现各种个性化分类内容展示而不互相干扰!
Google在Design support library中提供官方的Tab组件,它就是TabLayout。
相比Github上面开源的第三方库,这个更加简单易用。

有以下常用属性:
app:tabGravity="fill" 表示TabLayout中的Tabs要占满屏幕的width;
app:tabSelectedTextColor:Tab被选中字体的颜色;
app:tabTextColor:Tab未被选中字体的颜色;
app:tabIndicatorColor:Tab指示器下标的颜色;
-->
<android.support.design.widget.TabLayout
android:id="@+id/id_tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabGravity="fill"
app:tabIndicatorColor="@color/main_white" />

</android.support.design.widget.AppBarLayout>

<!--
我们常用的ViewPager,不多说了。你会发现多了一个 app:layout_behavior 属性,没错,
如果你使用CoordinatorLayout来实现Toolbar滚动渐变消失动画效果,那就必须在它下面的那个控件中加入这个属性,
并且下面的这个控件必须是可滚动的。
当设置了layout_behavior的控件滑动时,就会触发设置了layout_scrollFlags的控件发生状态的改变。
-->
<android.support.v4.view.ViewPager
android:id="@+id/id_viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />


<!--
这是一个浮动按钮。由于FloatingActionButton是重写ImageView的,
所有FloatingActionButton拥有ImageView的一切属性。

属性介绍:
app:backgroundTint : FAB的背景色。
app:elevation :FAB的阴影效果。
app:rippleColor :设置涟漪的颜色,默认是由背景色生成的暗色调,可以自己指定。
app:pressedTranslationZ :FAB动画效果,在它被按下的时候阴影就会增大。
-->
<android.support.design.widget.FloatingActionButton
android:id="@+id/id_floatingactionbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:src="@mipmap/ic_action_plusone"
app:backgroundTint="@color/main_blue_light"
app:elevation="6dp"
app:pressedTranslationZ="12dp"
app:rippleColor="@color/main_blue_dark" />

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

frag_main.xml源码(Fragment的布局)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="utf-8"?>


<!--

SwipeRefreshLayout是伟大的Google在v4包中给出的下拉刷新组件。

-->
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/id_swiperefreshlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

<!--
使用RecyclerView需要在build.gradle中添加
compile 'com.android.support:recyclerview-v7:22.2.0'
-->
<android.support.v7.widget.RecyclerView
android:id="@+id/id_recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />


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

item_main.xml源码(RecyclerView中item)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!--
CardView就是一个卡片样式的FrameLayout。

参数介绍:
app:cardBackgroundColor : 背景颜色
app:cardCornerRadius : 设置圆角。
app:cardElevation : 阴影。
app:cardMaxElevation : 最大阴影。
app:cardPreventCornerOverlap : 在v20和之前的版本中添加内边距,
这个属性是为了防止卡片内容和边角的重叠。

app:cardUseCompatPadding : 设置内边距,v21+的版本和之前的版本仍旧具有一样的计算方式
-->
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/id_cardview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:cardBackgroundColor="@color/main_blue_light"
app:cardCornerRadius="4dp"
app:cardElevation="5dp"
app:cardMaxElevation="10dp"
app:cardPreventCornerOverlap="true"
app:cardUseCompatPadding="true">

<TextView
android:id="@+id/id_textview"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center"
android:gravity="center"
android:textColor="@color/main_white"
android:textSize="30sp" />

</android.support.v7.widget.CardView>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?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_menu_home"
android:icon="@mipmap/ic_home_white_48dp"
android:title="主页" />

<item
android:id="@+id/nav_menu_categories"
android:icon="@mipmap/ic_sort_by_alpha_white_48dp"
android:title="分类" />

<item
android:id="@+id/nav_menu_feedback"
android:icon="@mipmap/ic_message_white_48dp"
android:title="反馈" />
<item
android:id="@+id/nav_menu_setting"
android:icon="@mipmap/ic_settings_white_48dp"
android:title="设置" />

</group>
</menu>

header_nav.xml源码(NavagationView的head)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?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="220dp"
android:background="@drawable/ic_user_background"
android:gravity="center"
android:orientation="vertical">

<!--
一个显示圆形头像的自定义ImageView
-->
<com.sunjiajia.androidnewwidgetsdemo.view.RoundedImageView
android:id="@+id/id_header_face"
android:layout_width="110dp"
android:layout_height="110dp"
android:scaleType="fitXY"
android:src="@drawable/author" />

<TextView
android:id="@+id/id_header_authorname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/header_author_name"
android:textColor="@android:color/black"
android:textSize="16sp" />

<TextView
android:id="@+id/id_header_url"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/header_author_url"
android:textColor="@android:color/black"
android:textSize="18sp" />
</LinearLayout>

Java代码

Java代码写法比较简单,这里只给出RecyclerView.Adapter的写法(包括item点击事件)。

###RecyclerView.Adapter写法源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package com.sunjiajia.androidnewwidgetsdemo.adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.sunjiajia.androidnewwidgetsdemo.R;

import java.util.ArrayList;
import java.util.List;

/**
* Created by Monkey on 2015/6/29.
*/
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewHolder> {

// 点击事件接口
public interface OnItemClickListener {
void onItemClick(View view, int position);

void onItemLongClick(View view, int position);
}

public OnItemClickListener mOnItemClickListener;

public void setOnItemClickListener(OnItemClickListener listener) {
this.mOnItemClickListener = listener;
}


public Context mContext;
public List<String> mDatas;
public LayoutInflater mLayoutInflater;

public MyRecyclerViewAdapter(Context mContext) {
this.mContext = mContext;
mLayoutInflater = LayoutInflater.from(mContext);
// 这里是模拟数据。
mDatas = new ArrayList<>();
for (int i = 'A'; i <= 'z'; i++) {
mDatas.add((char) i + "");
}
}

/**
* 创建ViewHolder
*/
@Override
public MyRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View mView = mLayoutInflater.inflate(R.layout.item_main, parent, false);
MyRecyclerViewHolder mViewHolder = new MyRecyclerViewHolder(mView);
return mViewHolder;
}

/**
* 绑定ViewHoler,给item中的控件设置数据
*/
@Override
public void onBindViewHolder(final MyRecyclerViewHolder holder, final int position) {
//点击事件在这里实现,主要是利用RecyclerView中填充的布局控件可以被点击这个原理
if (mOnItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onItemClick(holder.itemView, position);
}
});

// 长点击事件
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mOnItemClickListener.onItemLongClick(holder.itemView, position);
return true;
}
});

}

holder.mTextView.setText(mDatas.get(position));
}

@Override
public int getItemCount() {
return mDatas.size();
}
}

MyRecyclerViewHolder.java源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.sunjiajia.androidnewwidgetsdemo.adapter;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;

import com.sunjiajia.androidnewwidgetsdemo.R;

/**
* Created by Monkey on 2015/6/29.
*/
public class MyRecyclerViewHolder extends RecyclerView.ViewHolder {

public TextView mTextView;

public MyRecyclerViewHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView.findViewById(R.id.id_textview);
}
}

结语

在源码中学习Android,是有种身临其境的感觉的。

整个Demo的源码我放在了GitHub上,谢谢star一下~
在看源码过程中如果发现什么问题,请在留言,看到一定回复。

源码地址:
AndroidNewWidgetsDemo

##清纯妹子
清纯妹子


欣慰帮到你 一杯热咖啡
【奋斗的Coder!】企鹅群
【奋斗的Coder】公众号
CATALOG
  1. 1. 前言
    1. 1.1. 效果动图GIF:
  2. 2. 学习内容
    1. 2.1. 主布局activity_my.xml源码(重点)
    2. 2.2. content_main.xml源码(重点)
    3. 2.3. frag_main.xml源码(Fragment的布局)
    4. 2.4. item_main.xml源码(RecyclerView中item)
    5. 2.5. menu_nav.xml的源码(NavagationView中菜单)
    6. 2.6. header_nav.xml源码(NavagationView的head)
  3. 3. Java代码
    1. 3.1. MyRecyclerViewHolder.java源码
  4. 4. 结语