介绍
CoordinatorLayout是用来协调其子view们之间动作的一个父view,而Behavior就是用来给CoordinatorLayout的子view们实现交互的。
SUM
1. CollapsingToolbarLayout_伸缩折叠工具
参考:看,这个工具栏能伸缩折叠——Android CollapsingToolbarLayout使用介绍
a. CollapsingToolbarLayout折叠或展开时,FloatingActionButton跟随运动并且大小相应变化.CollapsingToolbarLayout是专门用来实现子布局内不同元素响应滚动细节的布局。
b. AppBarLayout是一种支持响应滚动手势的app bar布局(比如工具栏滚出或滚入屏幕);与AppBarLayout组合的滚动布局(Recyclerview、NestedScrollView等)需要设置app:layout_behavior="@string/appbar_scrolling_view_behavior"(上面代码中NestedScrollView控件所设置的)。没有设置的话,AppBarLayout将不会响应滚动布局的滚动事件。。
c. CollapsingToolbarLayout和ScrollView一起使用会有滑动bug,注意要使用NestedScrollView来替代ScrollView。
Android studio中有一个Activity模板叫ScrollingActivity,它实现的就是简单的可折叠工具栏。
ScrollingActivity的布局代码如下:
<?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"
android:fitsSystemWindows="true"
tools:context="com.jack.jack_junit_demo.ScrollingActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:fitsSystemWindows="true"
android:layout_height="180dp"
android:layout_width="match_parent"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:contentScrim="?attr/colorPrimary">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<!--可以include 抽取出来-->
<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="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:text="@string/large_text" />
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
app:layout_anchor="@id/app_bar"
app:layout_anchorGravity="bottom|end"
android:src="@android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>
2.AppBarLayout的子布局有5种滚动标识
就是上面代码CollapsingToolbarLayout中配置的app:layout_scrollFlags属性:
- scroll:将此布局和滚动时间关联。这个标识要设置在其他标识之前,没有这个标识则布局不会滚动且其他标识设置无效。
- enterAlways:任何向下滚动操作都会使此布局可见。这个标识通常被称为“快速返回”模式。
- enterAlwaysCollapsed:假设你定义了一个最小高度(minHeight)同时enterAlways也定义了,那么view将在到达这个最小高度的时候开始显示,并且从这个时候开始慢慢展开,当滚动到顶部的时候展开完。
- exitUntilCollapsed:当你定义了一个minHeight,此布局将在滚动到达这个最小高度的时候折叠。
- snap:当一个滚动事件结束,如果视图是部分可见的,那么它将被滚动到收缩或展开。例如,如果视图只有底部25%显示,它将折叠。相反,如果它的底部75%可见,那么它将完全展开。
3.CollapsingToolbarLayout的contentScrim、statusBarScrim 属性。
- app:contentScrim设置折叠时工具栏布局的颜色
- app:statusBarScrim设置折叠时状态栏的颜色。
默认contentScrim是colorPrimary的色值,statusBarScrim是colorPrimaryDark的色值。这个后面会用到。
4.CollapsingToolbarLayout子布局设置折叠模式,app:layout_collapseMode**
- off:这个是默认属性,布局将正常显示,没有折叠的行为。
- pin:CollapsingToolbarLayout折叠后,此布局将固定在顶部。
- parallax:CollapsingToolbarLayout折叠时,此布局也会有视差折叠效果
当CollapsingToolbarLayout的子布局设置了parallax模式时,我们还可以通过
app:layout_collapseParallaxMultiplier
设置视差滚动因子,值为:0~1。
5.FloatingActionButton
FloatingActionButton这个控件通过app:layout_anchor这个设置锚定在了AppBarLayout下方。FloatingActionButton源码中有一个Behavior方法,当AppBarLayout收缩时,FloatingActionButton就会跟着做出相应变化。关于CoordinatorLayout和Behavior,我下一篇文章会和大家一起学习。
B站很早就开源了一个弹幕引擎,还起了个狂拽酷炫吊炸天的名字叫“烈焰弹幕使 ”(一看就是二次元程序猿们的作品→_→),源码在github上,项目名叫DanmakuFlameMaster。
2. 自定义CoordinatorLayout的Behavior
自定义Behavior模仿知乎
参考:http://www.jianshu.com/p/488283f74e69
1.先看下布局
<?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/behavior_demo_coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways|snap"
android:background="?attr/colorPrimary" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/behavior_demo_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/behavior_demo_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</android.support.v4.widget.SwipeRefreshLayout>
<!--行为,依赖于自定义Beavior-->
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="16dp"
android:layout_marginBottom="72dp"
android:src="@android:drawable/ic_dialog_email"
app:layout_behavior="com.example.zcp.coordinatorlayoutdemo.behavior.MyFabBehavior"
android:layout_gravity="bottom|right" />
<!--行为,依赖于自定义Beavior-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="bottom"
android:background="@color/colorPrimary"
android:gravity="center"
app:layout_behavior="com.example.zcp.coordinatorlayoutdemo.behavior.MyBottomBarBehavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#ffffff"
android:text="这是一个底栏"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
SwipeRefreshLayout、FloatingActionButton和当做底栏的LinearLayout上有一个app:layout_behavior配置。
SwipeRefreshLayout配置的"@string/appbar_scrolling_view_behavior"是系统提供的,用来使滑动控件与AppBarLayout互动。
FloatingActionButton和底栏上配置的是我们接下来要自定义的Behavior。
先看FloatingActionButton的Behavior。
public class MyFabBehavior extends CoordinatorLayout.Behavior<View> {
private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();
private float viewY;//控件距离coordinatorLayout底部距离
private boolean isAnimate;//动画是否在进行
public MyFabBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
if (child.getVisibility() == View.VISIBLE && viewY == 0) {
//获取控件距离父布局(coordinatorLayout)底部距离
viewY = coordinatorLayout.getHeight() - child.getY();
}
return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;//判断是否竖直滚动
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
//大于0是向上滚动 小于0是向下滚动
if (dy >= 0 && !isAnimate && child.getVisibility() == View.VISIBLE) {
hide(child);
} else if (dy < 0 && !isAnimate && child.getVisibility() == View.GONE) {
show(child);
}
}
//隐藏时的动画
private void hide(final View view) {
ViewPropertyAnimator animator = view.animate().translationY(viewY).setInterpolator(INTERPOLATOR).setDuration(200);
animator.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
isAnimate = true;
}
@Override
public void onAnimationEnd(Animator animator) {
view.setVisibility(View.GONE);
isAnimate = false;
}
@Override
public void onAnimationCancel(Animator animator) {
show(view);
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
animator.start();
}
//显示时的动画
private void show(final View view) {
ViewPropertyAnimator animator = view.animate().translationY(0).setInterpolator(INTERPOLATOR).setDuration(200);
animator.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
view.setVisibility(View.VISIBLE);
isAnimate = true;
}
@Override
public void onAnimationEnd(Animator animator) {
isAnimate = false;
}
@Override
public void onAnimationCancel(Animator animator) {
hide(view);
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
animator.start();
}
}
逻辑并不复杂,我们通过重写Behavior中关于嵌套滑动的两个回调完成了FloatingActionButton的隐藏和显示判断及操作。
单独出场的底栏也可以利用上面一样的方法来设置隐藏或显示,我的底栏是和AppBarLayout一起出场,所以我就让底栏从属于AppBarLayout活动。代码如下:
public class MyBottomBarBehavior extends CoordinatorLayout.Behavior<View> {
public MyBottomBarBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
//这个方法是说明这个子控件是依赖AppBarLayout的
return dependency instanceof AppBarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
float translationY = Math.abs(dependency.getTop());//获取更随布局的顶部位置
child.setTranslationY(translationY);
return true;
}
}
代码量比上个还少。我们还可以通过重写onMeasureChild()来使控件响应从属控件的大小变化。
Behavior提供的很多,我这里用到的只是一部分,大家可以看看源码,根据具体需求去使用。
3 .CollapsingToolbarLayout与TabLayout结合
CollapsingToolbarLayout与TabLayout组合使用的效果也不错。
<?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"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:titleEnabled="false"
android:fitsSystemWindows="true"
app:contentScrim="@color/colorPrimary"
app:statusBarScrim="@android:color/transparent"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<ImageView
android:id="@+id/imageview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:adjustViewBounds="true"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.7"
android:fitsSystemWindows="true"
android:src="@drawable/girl2"/>
<View
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/gradient"
android:fitsSystemWindows="true" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="96dp"
android:minHeight="?attr/actionBarSize"
android:gravity="top"
app:layout_collapseMode="pin"
app:title="hello"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:titleMarginTop="15dp"
/>
<android.support.design.widget.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_gravity="bottom" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewpage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
</android.support.v4.view.ViewPager>
</android.support.design.widget.CoordinatorLayout>
2. AppBarLayout
- SwipeRefreshLayout配置的"@string/appbar_scrolling_view_behavior"是系统提供的,用来使滑动控件与AppBarLayout互动。
网友评论