《Android第一行代码》书籍划重点记录

1.1.1 Android系统架构

Android大致可以分为四层架构:Linux内核层、系统运行库层、应用框架层和应用层。

1. Linux内核层

Android系统是基于Linux内核的,这一层为Android设备的各种硬件提供了底层的驱动,如显示驱动、音频驱动、照相机驱动、蓝牙驱动、Wi-Fi驱动、电源管理等。

2. 系统运行库层

这一层通过一些C/C++库来为Android系统提供了主要的特性支持。如SQLite库提供了数据库的支持,OpenGL|ES库提供了3D绘图的支持,Webkit库提供了浏览器内核的支持等。

同样这一层还有Android运行时库,它主要提供了一些核心库,能够允许开发者使用java语言来编写Android应用。

3. 应用框架层

这一层主要提供了构建应用程序时可能用到的各种API,Android自带的一些核心应用就是使用这些API完成的,开发者也可以通过使用这些API来构建自己的应用程序。

4. 应用层

所有安装在手机上的应用程序都属于这一层的,比如系统自带的联系人、短信等程序,或者是你从Google Play上下载的小游戏,当然还包括你自己开发的程序。

 

1.1.3 Android应用开发特色

1. 四大组件

Android系统四大组件分别是活动(Activity)、服务(Service)、广播接收器(Broadcast Receiver)和内容提供器(Content Provider)。其中活动是所有Android应用程序的门面,凡是在应用中你看到的东西,都是放在活动中的。而服务就比较低调了,你无法看到他,但他会一直在后台默默的运行,即使用户退出了应用,服务仍然是可以继续运行的。广播接收器运行你的应用接收来自各处的广播消息。比如电话、短信等,当然你的应用同样也可以向外发出广播消息。内容提供器则为应用程序之间共享数据提供了可能,比如你想要读取系统电话簿中的联系人,就需要通过内容提供器来实现。

 

1.3.6 详解build.gradle文件

apply plugin: 'com.android.application' //表示这是一个应用程序模块

//apply plugin: 'com.android.libray' //表示这是一个库模块

android { //android闭包

compileSdkVersion 25 //指定项目编译版本

buildToolsVersion "25.0.2" //指定项目构建工具版本

defaultConfig { //defaultConfig闭包

applicationId "com.example.activitytest" //项目包名

minSdkVersion 15 //项目最低兼容Android系统版本

targetSdkVersion 25 //最高兼容Android系统版本

versionCode 1 //项目版本号

versionName "1.0" //项目版本名

}

buildTypes { //buildTypes闭包

release { //指定生成安装文件的相关配置

minifyEnabled false //指定是否对项目代码进行混淆

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' //指定混淆是使用的规则文件

}

}

}


dependencies { //dependencies闭包

compile fileTree(dir: 'libs', include: ['*.jar']) //添加libs目录下所有.jar文件

compile 'com.android.support:appcompat-v7:25.3.1' //声明远程依赖

testCompile 'junit:junit:4.12'

}

 

2.2.2 创建和加载布局

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical" android:layout_width="match_parent"

android:layout_height="match_parent">


<Button

android:id="@+id/button_1"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="Button1"/>

</LinearLayout>

android:id 是给当前的元素定义个唯一标识符。

match_parent 表示让当前元素和父元素一样宽。

wrap_content 表示当前元素的高度只要能刚好包含里面的内容。

 

2.4.3 活动的生存期

onCreate() 活动第一次被创建的时候调用。

onStart() 活动由不可见变为可见的时候调用。

onResume() 活动准备好和用户进行交互的时候调用。

onPause() 系统准备去启动或者恢复另一个活动的时候调用。

onStop() 活动完全不可见的时候调用。

onDestory() 活动被销毁之前调用。

onRestart() 活动由停止状态变为运行状态之前调用。

 

完整生存期。活动在onCreate()方法和onDestory方法之间所经历的,就是完整生存期。一般情况下,一个活动会在onCreate()方法中完成各种初始化操作,而在onDestroy()方法中完成释放内存操作。

可见生存期。活动在onstart()方法和onStop()方法之间所经历的,就是可见生存期。在可见生存期内,活动对于用户总是可见的,即便有可能无法和用户进行交互。我们可以通过这两个方法,合理的管理那些对用户可见的资源。比如在onStart()方法中对资源进行加载,而在onStop方法中对资源进行释放,从而保证处于停止状态的活动不会占用过多内存。

前台生存期。活动在onResume()方法和onPause()方法之间所经历的就是前台生存期。在前台生存期内,活动总是处于运行状态的,此时的活动是可以和用户进行交互的,我们平时看到和接触最多的也就是这个状态下的活动。

 

2.5 活动的启动模式

启动模式一共有4种,分别是 standard、singleTop、singleTask 和 singleInstance。

2.5.1 standard

使用standard模式的活动,系统不会在乎这个活动是否已经再返回栈中存在,每次启动都会创建该活动的一个新的实例。

2.5.2 singleTop

当活动的启动模式指定为singleTop,在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。

2.5.3 singleTask

当活动的启动模式指定为 singleTask,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。

2.5.4 singleInstance

指定为singleInstance 模式的活动会启用一个新的返回栈来管理这个活动,在这种模式下会有一个单独的返回栈来管理这个活动,不管是那个应用程序来访问这个活动,都公用的同一个返回栈,也就解决了共享活动实例的问题。

 

3.2.1 TextView

用于在界面上显示一段文本信息。

android:layout_width="match_parent"

android:layout_height="wrap_content"

match_parent 表示让当前控件的大小和父布局的大小一样,也就是由父布局来决定当前控件的大小。

wrap_content 表示让当前空间的大小能够刚好包含住里面的内容,也就是由控件内容决定当前控件的大小。

android:layout_gravity="center"

android:gravity 指定文字的对齐方式值为 center 表示文字在垂直和水平方向都居中对齐。

 

3.2.3 EditText

允许用户在控件里输入和编辑内容,并可以在程序中对这些内容进行处理。

android:hint="Type something here"

android:maxLines="2"

使用 android:hint 属性指定了一段提示性的文本。

android:maxLines 指定了EditText的最大行数为两行。

 

3.2.5 ProgressBar

ProgressBar 用于在界面上显示一个进度条,表示我们的程序正在加载一些数据。

style="?android:attr/progressBarStyleHorizontal"

android:max="100"

style="?android:attr/progressBarStyleHorizontal" 指定为水平进度条。

 

3.3 详解4中基本布局

3.3.1 线性布局

LinearLayout 又称作线性布局,是一种非常常见的布局。该布局会将它所包含的空间在线性方向上依次排列。

 

android:orientation="vertical"

通过android:orientation 属性指定排列方向。verical 为垂直方向排列, horizontal 为水平方向排列。

当 LinearLayout 的排列方向是 horizontal 时,只有垂直方向上的对齐方式才会生效,当 LinearLayout 的排列方向是 vertical 时,只有水平方向的对齐方式才会生效。

 

3.3.2 相对布局

RelativeLayout 又称作相对布局,他可以通过相对定位的方式让控件出现在布局的任何位置。

 

3.3.3 帧布局

FrameLayout 又称作帧布局,这种布局没有方便的定位方式,所有的控件都会默认摆放在布局的左上角。

 

3.3.4 百分比布局

PercentFrameLayout 为百分比布局,在这种布局中我们可以不再使用wrap_content、match_parent 等方式来指定控件的大小,而是允许直接指定控件在布局中所占的百分比。

 

3.6 更强大的滚动控件——RecyclerView

RecyclerView 可以说是一个增强版的 ListView,不仅可以轻松实现和 ListView 同样的效果,还优化了ListView 中存在的各种不足之处。

 

5.1 广播机制简介

Broadcast Receiver (广播接收器)

Android中的广播主要可以分为两种类型:标准广播和有序广播:

标准广播(Normal broadcasts)是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着他是无法被截断的。

有序广播(Ordered broadcasts)则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。

 

6.2 文件存储

6.2.1 将数据存储到文件中

Context 类中提供了一个 openFileOutput() 方法,可以用于将数据存储到指定的文件中,该方法接收两个参数,第一个参数是文件名,第二个参数是文件的操作模式。

openFileOutput() 方法返回的是一个FileOutpuStream 对象,得到这个对象之后就可以使用java流的方式将数据写入到文件中了。

6.2.2 从文件中读取数据

Context类中提供了一个openFileInput() 方法,用于从文件中读取数据,该方法接收的参数为要读取的文件名。

 

6.3 SharedPreferences 存储

ShearedPreferences 是使用键值对的方式来存储数据的,当保存一条数据的时候,需要给这条数据提供一个对应的键,这样在读取数据的时候就可以通过这个键把相应的值取出来。

 

6.4 SQLite 数据库存储

6.4.1 创建数据库

Android 为了让我们能够更加方便的管理数据库,专门提供了一个 SQLiteOpenHelper 帮助类,借助这个类就可以对数据库进行创建和升级。

SQLiteOpenHelper 中有两个非常重要的实例方法:getReadableDatabase() 和getWritableDatavase()。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个对数据库进行读写的操作的对象。

6.4.3 添加数据

对数据进行操作无非有4种,即 CRUD。其中 C 代表添加(Create),R 代表查询(Retrieve),U 代表更新(Update),D 代表删除(Delete)。

SQL 语言中添加数据时使用 insert,查询数据时使用 select,更新数据时使用 update,删除数据时使用delete。

SQLiteDatavase 中提供了一个 insert() 方法,这个方法就是专门用于添加数据的,它接收3个参数,第一个参数是表名,第二个参数用户在位指定添加数据的情况下给某些可为空的列自动赋值NULL,第三个参数是一个ContentValues对象。

6.4.4 更新数据

SQLiteDatabase 中提供了 update 方法用于对数据进行更新,这个方法接收4个参数,第一个为表名,第二个是 ContentValues 对象,要把更新的数据在这里组装进去。第三四个个参数用于约束更新某一行或者某几行中的数据,不指定的话默认更新所有行。

6.4.5 删除数据

SQLiteDatabase 中提供了 delete() 方法用于删除数据,这个方法接收3个参数,第一个参数为表名,第二、第三个参数用于约束删除某一行或者某几行的数据,不指定的话默认删除所有行。

6.4.6 查询数据

SQLiteDatabase 中提供了 query()方法用于对数据进行查询,这个方法接收7个参数,第一个为表名,第二个参数用于指定查询那几列,如果不指定默认查询所有列,第三、第四个参数用于约束查询某一行或某几行的数据,不指定默认查询所有行,第五个参数用于指定需要去 group by的列,不指定表示不对查询结果进行 group by 操作,第六个参数用于对 group by 之后的数据进行进一步过滤,不指定表示不过滤,第七个参数用于指定查询结果的排列方式,不指定表示使用默认排序。

 

6.5 使用 LitePal 操作数据库

LitePal 是一款开源的Android 数据库框架,它采用了对象关系映射(ORM)的模式,并将我们平时开发最常用到的一些数据库功能进行了封装,使得不用编写一行SQL语句就可以完成各种建表和增删改查的操作。

6.5.2 配置 LitePal

编辑 app/build.gradle 文件,在 dependencies 闭包中添加

compile 'org.litepal.android:core:1.3.2'


dependencies { //dependencies闭包

compile fileTree(dir: 'libs', include: ['*.jar']) //添加libs目录下所有.jar文件

compile 'com.android.support:appcompat-v7:25.3.1' //声明远程依赖

testCompile 'junit:junit:4.12'

compile 'org.litepal.android:core:1.3.2' //配置LitePal

}

接下来需要配置 litepal.xml 文件,在项目assets 目录下创建 litepal.xml 文件。

<?xml version="1.0" encoding="utf-8"?>

<litepal>

<!--指定数据库名-->

<dbname value="BookStore"></dbname>

<!--数据库版本号-->

<version value="2"></version>

<!--指定映射模型-->

<list>

<!--声明要配置的映射模型类-->

<mapping class="com.example.hds.litepaltest.Book"></mapping>

<mapping class="com.example.hds.litepaltest.Category"></mapping>

</list>

</litepal>

最后还需配置下 LitePalApplication,将项目的 application 配置为 org.litepal.LitePalApplication

<application

android:name="org.litepal.LitePalApplication"

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name">

</application>

 

6.5.3 创建和升级数据库

使用<mapping>标签来声明我们要配置的映射模型类,注意一定要使用完整的类名。

<mapping class="com.example.litepaltest.Book"></mapping>

 

调用 LitePal.getDatabase() 方法自动创建数据库。

 

6.5.4 使用 LitePal 添加数据

LitePal 进行 CRUD 操作需要继承 DataSupport 类。

调用 save() 方法就能完成数据添加操作了。

 

6.5.5 使用 LitePal 更新数据

调用 updateAll() 方法去执行更新操作。方法中可指定一个条件约束,如果不指定就表示更新所有数据。这里我们将所有书名是 The Lost Symbol 并且作者是 Dan Brown 的书价格更新为 14.95,出版社更新为 Anchor。

Book book = new Book();

book.setPrice(14.95);

book.setPress("Anchor");

//更新数据 (将所有书名是The Lost Symbol并且作者是Dan Brown的书架更新为14.95出版社更新为Anchor)

book.updateAll("name = ? and author = ?", "The Lost Symbol", "Dan Brown");

 

6.5.6 使用 LitePal 删除数据

调用 DataSupport.deleteAll() 方法删除数据,该方法第一个参数用于指定删除那张表,第二个参数用于指定约束条件。下面代码意思是,删除Book 表中价格低于 15 的书。

//删除数据 (删除Book表中价格低于15的书)

DataSupport.deleteAll(Book.class, "price < ?", "15");

 

6.5.7 使用LitePal 查询数据

调用 DataSupport.findAll() 方法查询数据,findAll() 方法的返回值是一个Book 类型的 List 集合。

//查询数据

List<Book> books = DataSupport.findAll(Book.class);

for(Book book : books) {

Log.d(TAG, "book name is " + book.getName());

Log.d(TAG, "book author is " + book.getAuthor());

Log.d(TAG, "book pages is " + book.getPages());

Log.d(TAG, "book price is " + book.getPrice());

Log.d(TAG, "book press is " + book.getPress());

}

查询Book 表中第一条数据:

//查询Book表中的第一条数据

Book firstBook = DataSupport.findFirst(Book.class);

select() 方法用户指定查询那几列数据,对应了SQL当中的select关键字。比如只查 name 和 author 这两列的数据:

//只查name和author这两列的数据

List<Book> books1 = DataSupport.select("name", "author").find(Book.class);

where() 方法用于指定查询的约束条件,对应了SQL当中的 where 关键字。比如只查页数大于400的数据:

//只查页数大于400的数据

List<Book> books2 = DataSupport.where("pages > ?", "400").find(Book.class);

order() 方法用于指定结果的排序方式,对应SQL当中的 order by 关键字。比如将查询结果按照书价格从高到低排序:

//查询结果按书价格从高到低排序 (desc标识降序排列, asc标识升序排列)

List<Book> books3 = DataSupport.order("price desc").find(Book.class);

limit() 方法用于指定查询结果的数量,比如只查表中的前3条数据:

//指定查询结果的数量 (查表中前3条数据)

List<Book> books4 = DataSupport.limit(3).find(Book.class);

offset() 方法用于指定查询结果的便宜量,比如查询表中的第2、3、4条数据:

//指定查询结果的便宜量 (查询表中第2,3,4条数据)

List<Book> books5 = DataSupport.limit(3).offset(1).find(Book.class);

 

7.1 内容提供器简介

内容提供器(Content Provider)主要是用于在不同的应用程序之间实现数据共享的功能,他提供了一套完整的机制,运行一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性。目前,使用内容提供器是 Android 实现跨程序共享数据的标准方式。

 

8.2 使用通知

通知(Notification)是 Android 系统中比较有特色的一个功能,当某个应用程序希望向用户发出一些提示信息,而该应用程序又不在前台运行时,就可以借助通知来实现。发出一条通知后,手机最上方的状态栏中会显示一个通知的图标,下拉状态栏后可以看到通知的详细内容。

 

8.4 播放多媒体文件

8.4.1 播放音频

在 Android 中播放音频文件一般都是使用 MediaPlayer 类来实现的,它对多种格式的音频文件提供了非常全面的控制方法,从而使得播放音乐的工作变得十分简单。

首先需要创建出一个 MediaPlayer 对象,然后调用 setDataSoure() 方法来设置音频文件的路径,在调用 prepare() 方法使 MediaPlayer 进入到准备状态,接下来调用 start() 方法就可以开始播放音频,调用 pause() 方法就会暂停播放,调用 reset() 方法就会停止播放。

 

8.4.2 播放视频

播放视频文件只要是使用 VideoView 类来实现的,这个类将视频的显示和控制集于一身,使得我们仅仅借助它就可以完成一个建议的视频播放器。

setVideoPath() 设置要播放的视频文件的位置

start() 开始或继续播放视频

pause() 暂停播放视频

resume() 将视频重头开始播放

seekTo() 从指定的位置开始播放视频

isPlaying() 判断当前是否正在播放视频

getDuration() 获取载入的视频文件的时长

 

9.2 使用 HTTP 协议访问网络

Android 发送 HTTP 请求的两种方式 HttpURLConnection 和 HttpClient,在Android6.0系统中,HttpClient 功能被移除现在官方建议使用 HttpURLConnection。

利用BufferedReader 对服务器返回的流进行读取。

通过 runOnUiThread() 方法将线程切换到主线程。

 

9.2.2 使用OkHttp

OkHttp 不仅在接口封装上面做的简单易用,在底层实现上也是自成一派,比起原生的 HttpURLConnection,可以说是有过之而不及。

首先需要创建OkHttpClient 的实例。

调用 execute() 方法发送请求并获取服务器返回的数据。

OkHttpClient client = new OkHttpClient(); //创建OkHttpClient实例

Request request = new Request.Builder()

.url("http://www.baidu.com") //设置目标网络地址

.build();

//发送请求并获取服务器返回数据

Response response = client.newCall(request).execute();

String responseData = response.body().string(); //接收到的数据转为String

Log.d(TAG, "response==="+responseData);

 

9.4.1 使用 JSONObject

可使用 JSONObject 来解析JSON数据。

//使用JSONObject 解析JSON

private void parseJSONWithJSONObject(String jsonData) {

try {

JSONArray jsonArray = new JSONArray(jsonData);

for (int i=0; i<jsonArray.length(); i++) {

JSONObject jsonObject = jsonArray.getJSONObject(i);

String id = jsonObject.getString("id");

String name = jsonObject.getString("name");

String version = jsonObject.getString("version");

Log.d(TAG, "id is "+id);

Log.d(TAG, "name is "+name);

Log.d(TAG, "version is "+version);

}

} catch (JSONException e) {

e.printStackTrace();

}

}

循环遍历 JSONArray,从中取出的每一个元素都是一个JSONObject 对象,每个 JSONObject 对象中又包含 id、name 和 version 这些数据。接下来只需调用 getString() 方法将这些数据取出。

 

10.1 服务是什么

服务(Service)是Android 中实现程序后台运行的解决方案,它非常适合去执行那些不需要和用户交互而且还要求长期运行的任务。服务的运行不依赖与任何用户界面,即使程序被切换到后台,或者用户打开了另外一个应用程序,服务仍然能够保持正常运行。

 

10.2 Android 多线程编程

定义一个线程需要新建一个类继承自 Thread,然后重写父类的 run() 方法。

new Thread(new Runnable() { //匿名创建线程

    @Override

    public void run() {
     
    //处理具体逻辑

    }

}).start();

 

10.2.3 解析异步消息处理机制

Android 中的异步消息处理主要由4个部分组成:Message、Handler、MessageQueue 和 Looper。

1. Message

Message 是在线程之间传递的消息,它可以在内容携带少量的信息,用于在不同线程之间交换数据。

2. Handler

Handler 顾名思义也就是处理中的意思,它主要是用于发送和处理消息的。

3. MessageQueue

MessageQueue 是消息队列的意思,它主要用于存放所有通过Handler 发送的消息。这部分消息会一直存在于消息队列中,等待被处理。

4. Looper

Looper 是每个线程中的 MessageQueue 的管家,调用 Looper 的 loop 方法后,就会进入到一个无限循环当中,然后每当发现 MessageQueue 中存在一条消息,就会将它取出,并传递到Handler 的 handleMessage() 方法中。每个线程中也只会有一个 Looper 对象。

 

10.2.4 使用 AsyncTask

AsyncTask 实现原理也是基于异步消息处理机制的,可以十分简单的从子线程切换到主线程。

 

继承AsyncTask 指定3个泛型参数为:

Params。在执行 AsyncTask 时需要传入的参数,可用于在后台任务中使用。

Progress。在后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。

Result。当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型

 

经常需要用到的重写方法:

1. onPreExecute()

这个方法会在后台任务开始执行之前调用,用于进行一些界面上的初始化操作。

 

2. doInBackground(Params...)

这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。如果需要更新 UI 元素,可以调用 publishProgress(Progress...) 方法来完成。

 

3. onProgressUpdate(Progress...)

当在后台任务中调用了 publishProgress(Progress...) 方法后,onProgressUpdate(Progress...) 方法就会被调用,该方法中携带的参数就是在后台任务中传递过来的。

 

4. onPostExecute(Result)

当后台任务执行完毕并通过 return 语句进行返回时,这个方法就很快会被调用。

 

简单来说,使用 AsyncTask 的诀窍就是,在 doInBackground() 方法中执行具体的耗时任务,在 onProgressUpdate() 方法中进行 UI 操作,在 onPostExecute() 方法中执行一些任务的收尾工作。

 

启动AsyncTaks 任务:

new DownloadTask().execute();

 

10.3.1 定义一个服务

定义一个服务需要新建一个类继承 Service,并重写 onBind()方法。

public class MyService extends Service {

public MyService() {}


@Override

public IBinder onBind(Intent intent) {

return mBinder;

}

//服务创建时调用

@Override

public void onCreate() {

super.onCreate();

}

//每次服务启动的时候调用

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

return super.onStartCommand(intent, flags, startId);

}

//服务销毁的时候调用

@Override

public void onDestroy() {

super.onDestroy();

}

}

 

10.3.2 启动和停止服务

调用 startService() 方法启动MyService这个服务。

Intent startIntent = new Intent(this, MyService.class);

startService(startIntent); //启动服务

调用 stopService() 方法停止MyService服务。

Intent stopIntent = new Intent(this, MyService.class);

stopService(stopIntent); //停止服务

 

10.5.1 使用前台服务

前台服务会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。

调用 startForeground() 方法会让 MyService 变成一个前台服务,并在系统状态栏显示出来。

 

10.5.2 使用 intentService

IntentService 创建一个异步的、会自动停止的服务。

public class MyIntentService extends IntentService {


public MyIntentService() {

super("MyIntentService");

}


@Override

protected void onHandleIntent(@Nullable Intent intent) {

//处理具体逻辑

}


@Override

public void onDestroy() {

super.onDestroy();

}

}

 

12 最佳UI体验——Material Design

12.2 Toolbar(自定义标题栏)

自定义标题栏,继承了 ActionBar 的所有功能而且灵活性很高,可以配合其他控件完成一些 Material Design 效果。

<menu xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto">

<item

android:id="@+id/backup"

android:icon="@drawable/ic_backup"

android:title="Backup"

app:showAsAction="always" />

<item

android:id="@+id/delete"

android:icon="@drawable/ic_delete"

android:title="Delete"

app:showAsAction="ifRoom"/>

<item

android:id="@+id/settings"

android:icon="@drawable/ic_settings"

android:title="Settings"

app:showAsAction="never"/>

</menu>

app:showAsAction 指定按钮的显示位置, showAsAction 可选值为:always 表示永远显示在 Toolbar 中,如果屏幕空间不够则不显示;ifRoom 表示屏幕空间足够的情况下显示在 Toolbar 中,不够的话就显示在菜单当中;never 表示永远显示在菜单中。Toolbar 中的 action 按钮只会显示图标,菜单中的 action 按钮只会显示文字。

 

12.3.1 DrawerLayout(滑动菜单)

所谓的滑动菜单就是将一些菜单选项隐藏起来,而不是放置在主屏幕上,然后可以通过滑动的方式将菜单显示出来。

 

12.2.3 NavigationView(滑动菜单任意布局)

dependencies { //dependencies闭包

compile fileTree(dir: 'libs', include: ['*.jar']) //添加libs目录下所有.jar文件

compile 'com.android.support:appcompat-v7:25.3.1' //声明远程依赖

testCompile 'junit:junit:4.12'

//导入Design Support库

compile 'com.android.support:design:26.1.0'

//图片圆形化

compile 'de.hdodenhof:circleimageview:2.1.0'

}

第一行导入Design Support 库,第二行是一个开源项目 CircleImageView,它可以轻松实现图片圆形化功能。

<!--头像(将图片圆形化控件)-->

<de.hdodenhof.circleimageview.CircleImageView

android:id="@+id/icon_image"

android:layout_width="70dp"

android:layout_height="70dp"

android:src="@drawable/nav_icon"

android:layout_centerInParent="true" />

CircleImageView 是一个用于将图片圆形化的控件,他的用法和ImageView 基本一样,这里给它指定了一张图作为头像,然后设置为居中显示。

 

12.4.1 FloatingActionButton (悬浮按钮)

FloatingActionButton 是 Design Support 库中提供的控件,可以轻松实现悬浮按钮效果。

<!--悬浮按钮控件-->

<android.support.design.widget.FloatingActionButton

android:id="@+id/fab"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="bottom|end"

android:layout_margin="16dp"

android:src="@drawable/ic_done" />

layout_gravity 属性指定将这个控件放置于屏幕右下角,end 用法如果系统语言从左往右,那么end 就表示在右边,相反则在左边。

 

12.5 卡片式布局

卡片式布局也是 Materials Design 中提出的一个新的概念,它可以让页面中的元素看起来就像在卡片中一样,并且还能拥有圆角和投影。

 

12.5.1 CardView

CardView 是用于实现卡片式布局效果的重要控件,由 appcompat-v7 库提供。实际上,CardView 也是一个 FrameLayout,只是额外提供了圆角和阴影等效果,看上去会有立体的感觉。

<!--卡片式布局控件-->

<android.support.v7.widget.CardView

android:layout_width="match_parent"

android:layout_height="wrap_content"

app:cardCornerRadius="4dp"

android:elevation="5dp">


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

这里定义了一个 CardView 布局,通过 app:cardCornerRadius 属性指定卡片圆角弧度,数值越大圆角的弧度也越大。通过 app:elevation 属性指定卡片的高度,数值越大,投影范围越大,值越小投影范围也越小,投影效果越浓。

 

12.5.5 AppBarLayout

AppBarLayout 是一个垂直方向的 LinearLayout,它在内部做了很多滚动事件封装。将Toolbar 嵌套到 AppBarLayout 中可巧妙的实现View不遮挡Toolbar 效果。

<!--垂直向上的LinearLayout(线性布局)-->

<android.support.design.widget.AppBarLayout

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:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"

app:popupTheme="@style/ThemeOverlay.AppCompat.Light"

app:layout_scrollFlags="scroll|enterAlways|snap"/>


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

这里在Toolbar 中添加了一个 app:layout_scrollFlags 属性,并将这个属性的值指定成了 scroll|enterAlways|snap。其中,scroll 表示当 RecyclerView 向上滚动的时候,Toolbar 会跟着一起向上滚动并实现隐藏;enterAlways 表示当 RecyclerView 向下滚动的时候,Toolbar 会跟着一起向下滚动并重新显示。snap 表示当 Toolbar 还没有完全隐藏或显示的时候,会根据当前滚动的距离,自动选择隐藏还是显示。

 

12.6 SwipeRefreshLayout (下拉刷新)

SwipeRefreshLayout 用于实现下拉刷新功能的核心类,它是由 support-v4 库提供的。我们把想要实现下拉功能的控件放置到 SwipeRefreshLayout 中,就可以让这个控件支持下拉刷新。

<!--下拉刷新控件-->

<android.support.v4.widget.SwipeRefreshLayout

android:id="@+id/swipe_refresh"

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/recycler_view"

android:layout_width="match_parent"

android:layout_height="match_parent"/>


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

 

12.7.1 CollapsingToolbarLayout (可折叠式标题栏)

CollapsingToolbarLayout 是一个作用于Toolbar 基础之上的布局,它也是由 Design Support 库提供的。CollapsingToolbarLayout 可以让 Toolbar 的效果变得更加丰富,不仅仅是展示一个标题栏,而是能够实现非常华丽的效果。

<!--可折叠式标题栏-->

<android.support.design.widget.CollapsingToolbarLayout

android:id="@+id/collapsing_toolbar"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"

app:contentScrim="?attr/colorPrimary"

app:layout_scrollFlags="scroll|exitUntilCollapsed">

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

app:contentScrim 属性用于指定 CollapsingToolbarLayout 在趋于折叠状态以及折叠之后的背景色为 colorPrimary。app:layout_scrollFlages 属性值 scroll 表示 CollapsingToolbarLayout 会随着内容详情的滚动一起滚动,exitUntilCollapsed 表示当 CollapsingToolbarLayout 随着滚动完成折叠之后就保留在界面上,不再移除屏幕。

 

13.6.2 多窗口模式下的生命周期

针对进入多窗口模式时活动会被重新创建,可以在 AndroidManifest.xml 中添加如下配置:加入这行配置之后,不管是进入多窗口模式,还是横竖屏切换,活动都不会被重新创建,而是会将屏幕发生变化的事件通知到 Activity 的 onConfigurationChanged() 方法中。

<activity

android:name=".MainActivity"

android:label="Fruits"

android:configChanges="orientation|keyboardHidden|screenSize|screenLayout">

</activity>

 

13.6.3 禁用多窗口模式

<application

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name"

android:resizeableActivity="false"> <!--禁用多窗口模式-->

</application>

 

默认情况下,我们的应用可以随着手机旋转自由的切换横竖屏,如果想让应用不允许横竖屏切换,需要在 AndroidManifest.xml 的<activity> 标签中添加以下配置,portrait 表示只支持竖屏,landscape 表示只支持横屏。

<activity

android:name=".MainActivity"

android:label="Fruits"

android:screenOrientation="portrait">

</activity>

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值