本節(jié)主要講AppBarLayout,但是一講到AppBarLayout必然會講另外兩個布局,CoordinatorLayout和CollapsingToolbarLayout ,因為這三個布局一起使用的時候會產(chǎn)生非常炫酷的效果!前一篇文章我們講過CoordinatorLayout,說它是一個加強版的FrameLayout,不過它可以監(jiān)聽其所有子控件的各種事件,然后幫我們做出合理的相應(yīng)。但是它到底是怎樣監(jiān)聽各個子控件的呢?具體的用法接下來一一跟大家分享!
CoordinatorLayout

首先看看官方文檔的解釋:
加強版的Framelayout,兩種使用場景
- 作為頂層布局使用
- 作為具有一個或多個相互作用的子控件的容器
那么CoordinatorLayout是怎樣協(xié)調(diào)子view的呢?當(dāng)然是通過behavior。 app:layout_behavior="@string/appbar_scrolling_view_behavior"這是開發(fā)中最常見的behavior。通過給滑動控件設(shè)置behavior,CoordinatorLayout的子view通過這個behavior可以做出具體的響應(yīng)操作!對于behavior實怎樣操作的?內(nèi)部有哪些方法?我會單獨在討論的!
AppbarLayout

官網(wǎng)的描述是:AppbarLayout 是一個垂直方向的Linearlayout,它實現(xiàn)了material design控件的特征,通過手勢改變子view的動作。那么當(dāng)滑動手勢改變時,內(nèi)部的子view應(yīng)該提供怎樣的響應(yīng)動作呢?

app:layout_scrollFlags.//設(shè)置響應(yīng)動作
-
注意點:
image.png
AppbarLayout 嚴重依賴于CoordinatorLayout,必須用于CoordinatorLayout 的直接子View,如果你將AppbarLayout 放在其他的ViewGroup 里面,那么它的這些功能是無效的。
app:layout_scrollFlags的值有哪些?具體的效果是什么?

layout_scrollFlags有5種動作,分別是 scroll,enterAlways,enterAlwaysCollapsed,exitUntilCollapsed,snap
- scroll
int SCROLL_FLAG_SCROLL
The view will be scroll in direct relation to scroll events.
This flag needs to be set for any of the other flags to take effect.
If any sibling views before this one do not have this flag, then this value has no effect.
該屬性是:當(dāng)子view設(shè)置該屬性是,該子view會隨著滑動控件滾動而滾動。
<?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.support.design.widget.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll"
/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="35dp"
app:cardCornerRadius="4dp">
<TextView
android:id="@+id/fruit_content_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"/>
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>!

- enterAlways
SCROLL_FLAG_ENTER_ALWAYS
When entering (scrolling on screen) the view will scroll on any downwards scroll event,
regardless of whether the scrolling view is also scrolling.
This is commonly referred to as the 'quick return' pattern.
當(dāng)子view設(shè)置該屬性的時候,當(dāng)NestedScrollView向下滑動的時候,改子view直接向下滑動,不管NestedScrollView是否在滑動。注意:要與scroll 搭配使用,否者是不能滑動的。
<android.support.design.widget.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways"
/>
</android.support.design.widget.AppBarLayout>

-
enterAlwaysCollapsed
enterAlwaysCollapsed.png
enterAlwaysCollapsed 是對enterAlways 的補充,當(dāng)NestedScrollView向下滑動的時候,滑動View(也就是設(shè)置了enterAlwaysCollapsed 的View)下滑至折疊的高度,當(dāng)NestedScrollView到達滑動范圍的結(jié)束值的時候,滑動View剩下的部分開始滑動。這個折疊的高度是通過View的minimum height (最小高度)指定的
補充說明:要配合scroll|enterAlways 一起使用
<android.support.design.widget.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
/>
</android.support.design.widget.AppBarLayout>

-
exitUntilCollapsed
image.png
當(dāng)ScrollView 滑出屏幕時(也就時向上滑動時),滑動View先響應(yīng)滑動事件,滑動至折疊高度,也就是通過minimum height 設(shè)置的最小高度后,就固定不動了,再把滑動事件交給 NestedScrollView 繼續(xù)滑動。
<android.support.design.widget.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
/>
</android.support.design.widget.AppBarLayout>

-
snap
snap.png
在滾動結(jié)束時,如果視圖只是部分可見,那么它將被斷開并滾動到它最接近的邊緣。例如,如果視圖只顯示底部的25%,那么它將會被完全關(guān)閉。相反,如果它的底部75%是可見的,那么它就會被完全地滾動到視圖中。

介紹一下AppbarLayout幾個常用且重要的方法
- addOnOffsetChangedListener 當(dāng)AppbarLayout 的偏移發(fā)生改變的時候回調(diào),也就是子View滑動。
- getTotalScrollRange 返回AppbarLayout 所有子View的滑動范圍
- removeOnOffsetChangedListener 移除監(jiān)聽器
- setExpanded (boolean expanded, boolean animate)設(shè)置AppbarLayout 是展開狀態(tài)還是折疊狀態(tài),animate 參數(shù)控制切換到新的狀態(tài)時是否需要動畫
- setExpanded (boolean expanded) 設(shè)置AppbarLayout 是展開狀態(tài)還是折疊狀態(tài),默認有動畫
CollapsingToolbarLayout

CollapsingToolbarLayout 是對Toolbar的包裝并且實現(xiàn)了折疊app bar效果,使用時,要作為 AppbarLayout 的直接子View。CollapsingToolbarLayout有以下特性:
-
Collapsing title
image.png
當(dāng)布局全部可見的時候,title 是最大的,當(dāng)布局開始滑出屏幕,title 將變得越來越小,你可以通過setTitle(CharSequence) 來設(shè)置要顯示的標(biāo)題。
-
Content scrim(內(nèi)容紗布)
image.png

滑動到一個確定的閥值時將顯示或者隱藏內(nèi)容紗布,可以通過setContentScrim(Drawable)來設(shè)置紗布的圖片。
提醒:紗布可以是圖片也可以是顏色色值,如果要顯示顏色,在xml 布局文件中用contentScrim屬性添加,代碼如下:app:contentScrim="@color/colorPrimary"
-
Status bar scrim(狀態(tài)欄紗布)
image.png
當(dāng)CollapsingToolbarLayout滑動到一個確定的閥值時,狀態(tài)欄顯示或隱藏紗布,你可以通過setStatusBarScrim(Drawable)來設(shè)置紗布圖片。
-
Parallax scrolling children(有視差地滾動子View)
image.png
讓CollapsingToolbarLayout 的子View 可以有視差的滾動,需要在xml中用 添加如下代碼:
app:layout_collapseMode="parallax"
-
Pinned position children(固定子View的位置)
image.png
子View可以固定在全局空間內(nèi),這對于實現(xiàn)了折疊并且允許通過滾動布局來固定Toolbar 這種情況非常有用。在xml 中將collapseMode設(shè)為pin,代碼如下:
app:layout_collapseMode="pin"
接下來要實現(xiàn)這樣的效果:

布局
<?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:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:fitsSystemWindows="true">
<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"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="@+id/fruit_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:fitsSystemWindows="true"
app:layout_collapseMode="parallax" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="35dp"
app:cardCornerRadius="4dp">
<TextView
android:id="@+id/fruit_content_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp" />
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:src="@drawable/ic_comment"
app:layout_anchor="@id/appBar"
app:layout_anchorGravity="bottom|end" />
</android.support.design.widget.CoordinatorLayout>
代碼:
package com.jimmy.xg.materialdesigndemo;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
public class FruitActivity extends AppCompatActivity {
public static final String FRUIT_NAME = "fruit_name";
public static final String FRUIT_IMAGE_ID = "fruit_image_id";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fruit);
Intent intent = getIntent();
String fruitName = intent.getStringExtra(FRUIT_NAME);
int fruitImageId = intent.getIntExtra(FRUIT_IMAGE_ID, 0);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
ImageView fruitImageView = (ImageView) findViewById(R.id.fruit_image_view);
TextView fruitContentText = (TextView) findViewById(R.id.fruit_content_text);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
collapsingToolbar.setTitle(fruitName);
Glide.with(this).load(fruitImageId).into(fruitImageView);
String fruitContent = generateFruitContent(fruitName);
fruitContentText.setText(fruitContent);
}
private String generateFruitContent(String fruitName) {
StringBuilder fruitContent = new StringBuilder();
for (int i = 0; i < 500; i++) {
fruitContent.append(fruitName);
}
return fruitContent.toString();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}








