1、简介
AppBarLayout是一个垂直的LinearLayout,实现了MaterialDesign中app bar的scrolling gestures特性。AppBarLayout的子View应该声明想要具有的“滚动行为”,这可以通过layout_scrollFlags属性或是setScrollFlags()方法来指定。AppBarLayout只有作为CoordinatorLayout的直接子View时才能正常工作,为了让AppBarLayout能够知道何时滚动其子View,我们还应该在CoordinatorLayout布局中提供一个可滚动View,我们称之为scrolling view。scrolling view和AppBarLayout之间的关联,通过将scrolling view的Behavior设为AppBarLayout.ScrollingViewBehavior来建立。
AppBarLayout主要用来实现这样的功能:当位于同一父容器中的可滚动View发生滚动时,AppBarLayout会根据子View声明的滚动行为来对其子View进行相应的滚动。
app bar是Material Design中的一个概念,我们可以把它看做是一种ToolBar。我们把TooBar套上一层AppBarLayout,就能把顶部栏玩出各种花样。
2、如何使用
布局文件定义如下:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.study.androidother.DesignSupportLibrary.AppBarlayoutTestActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="AppBarLayout"
android:background="@color/colorPrimary"
android:gravity="center"
android:textColor="@color/white"
android:textSize="28sp"
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">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="20sp"
android:text="NestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\nNestedScrollView\n"/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
注意点:
1)、AppBarLayout的子view必须指定属性app:layout_scrollFlags
2)、CoordinatorLayout的子view必须有NestedScrollView或其子类
3)、NestedScrollView或其子类指定属性app:layout_behavior="@string/appbar_scrolling_view_behavior"
2、AppBarLayout的layout_scrollFlags
布局文件如下:
<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="?android:attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll" />
</android.support.design.widget.AppBarLayout>
1)、app:layout_scrollFlags="scroll"
2)、enterAlways。值设为enterAlways的View, 当ScrollView往下滚动时,该View会直接往下滚动。而不用考虑ScrollView是否在滚动。
app:layout_scrollFlags="scroll|enterAlways"
3)、exitUntilCollapsed。值设为exitUntilCollapsed的View,当这个View要往上逐渐“消逝”时,会一直往上滑动,直到剩下的的高度达到它的最小高度后,再响应ScrollView的内部滑动事件。
app:layout_scrollFlags="scroll|exitUntilCollapsed"
4)、enterAlwaysCollapsed:是enterAlways的附加选项,一般跟enterAlways一起使用,它是指,View在往下“出现”的时候,首先是enterAlways效果,当View的高度达到最小高度时,View就暂时不去往下滚动,直到ScrollView滑动到顶部不再滑动时,View再继续往下滑动,直到滑到View的顶部结束。
app:layout_scrollFlags="scroll|enerAlways|enterAlwaysCollapsed"
3、设置监听
监听AppBarLayout移动了多少距离
appBarLayout = (AppBarLayout) findViewById(R.id.app_bar_layout);
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
Log.i(TAG, "----onOffsetChanged--verticalOffset:" + verticalOffset + ",ScrollRange:" + appBarLayout.getTotalScrollRange());
}
});
appBarLayout.getTotalScrollRange()获取AppBarLayout可以移动的范围
4、注意
1)、AppBarLayout的滑动是通过AppBarLayout.Behavior实现。虽然布局文件没有指定AppBarLayout的Behavior,但是AppBarLayout的默认Behavior是AppBarLayout.Behavior。CoordinatorLayout的onTouchEvent()调用了AppBarLayout.Behavior的onTouchEvent()。
2)、在CoordinatorLayout中AppBarLayout作为dependency,NestedScrollView作为child。
5、AppBarLayout为什么可以滑动
下面是CoordinatorLayout的onTouchEvent方法:
public boolean onTouchEvent(MotionEvent ev) {
boolean handled = false;
final int action = ev.getActionMasked();
if (mBehaviorTouchView != null || (cancelSuper = performIntercept(ev, TYPE_ON_TOUCH))) {
// Safe since performIntercept guarantees that
// mBehaviorTouchView != null if it returns true
final LayoutParams lp = (LayoutParams) mBehaviorTouchView.getLayoutParams();
final Behavior b = lp.getBehavior();
if (b != null) {
handled = b.onTouchEvent(this, mBehaviorTouchView, ev);
}
}
}
performIntercept中会调用AppBarLayout的Behavior的onTouchEvent,Behavior的onTouchEvent返回true时就会给mBehaviorTouchView赋值为AppBarLayout。所以上面代码中就会把CoordinatorLayout的onTouchEvent交给AppBarLayout的onTouchEvent处理。因此就可以实现AppBarLayout的滑动。
当AppBarLayout的滑动后由于CoordinatorLayout的作用就会调用NestedScrollView设置的app:layout_behavior="@string/appbar_scrolling_view_behavior"让NestedScrollView也跟着AppBarLayout一起滑动。