第一ToolBar
这个就省略了,网上关于他的资料太多了
第二AppbarLayout
MD中,有很多控件已经封装了Behavior,它的behavior已经写好了,比如AppBarLayout已经封装了behavior,只需要通过setScollFlags()传入的参数,就可以控制它里面的behavior到底执行什么样的动作。
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbarlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="300dp"
android:minHeight="50dp"
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
app:title="首页"
android:gravity="bottom"
android:background="@color/colorAccent"
/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
滚动ScrollView的时候,toolBar也会跟着做出改变,我们看下这个属性的一些参数的含义
app:layout_scrollFlags=“scroll|enterAlways|enterAlwaysCollapsed”
scroll:AppbarLayout中的内容(本例子中的toolbar)也是ScrollView的一部分,随着NestScrollView的滚动而滚动。就好比AppbarLayout中的内容长在了ScrollView的头部。
scroll|enterAlways:注意,后一个属性依据前一个属性。如果只有后一个属性,而没有前一个属性那这个属性不会起任何作用。 这两个属性我们会发现向下滑动的时候跟scroll没有任何区别,但向下滑动的时候我们会发现,只要你向下滑动,AppbarLayout中的内容就会滑出来
scroll|enterAlways|enterAlwaysCollapsed:这个属性要设置最小高度。上滑的时候没有区别,但是向下滑动的时候会先滑出来最小高度。当滑动到劲头的时候,再把剩余的滑动出来。
scroll|exitUntilCollapsed:向下滑动的时候与scroll没什么区别,向上滑动的时候会先滑到最小高度,直到ScrollView滑动完之后,最小高度也保留在屏幕上。最小高度永远不会滑出屏幕。
scroll|snap:向下滑动的时候,如果滑动的隐藏范围大于显示范围会出现回弹的效果。
AppbarLayout的监听事件
appbar_layout = findViewById(R.id.appbar_layout);
//当AppbarLayout 的偏移发生改变的时候回调,也就是子View滑动
appbar_layout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int i) {
}
});
//返回子View的可滑动距离
appbar_layout.getTotalScrollRange();
//移除偏移监听器
appbar_layout.removeOnOffsetChangedListener(null);
三CollapsingToolbarLayout
可折叠的Toolbar
看下布局
<?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.support.design.widget.AppBarLayout
android:id="@+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapse_layout"
android:layout_width="match_parent"
android:layout_height="250dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@mipmap/timg"
app:layout_collapseMode="parallax"
/>
<android.support.v7.widget.Toolbar
android:id="@+id/appbar_layout_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="AppbarLayout"
app:titleTextColor="@android:color/white"
app:navigationIcon="@mipmap/more"
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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="222"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="333"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="444"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="555"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="666"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="777"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
看下代码
package com.dongnao.dn_vip_ui_15_2;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import com.dongnao.dn_vip_ui_15_2.utils.StatusBarUtils;
/**
* 折叠控件
*/
public class CollapsingToolbarLayoutActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collapsing_toolbar);
initView();
}
private void initView(){
final Toolbar toolbar = (Toolbar) findViewById(R.id.appbar_layout_toolbar);
//设置沉浸式状态栏
StatusBarUtils.setTranslucentImageHeader(this,0,toolbar);
//设置标题颜色
toolbar.setTitleTextColor(Color.TRANSPARENT);
//加载动作菜单
toolbar.inflateMenu(R.menu.layout_toolbar_menu);
AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appbar_layout);
final CollapsingToolbarLayout collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapse_layout);
collapsingToolbarLayout.setTitle("");
collapsingToolbarLayout.setCollapsedTitleTextColor(getResources().getColor(R.color.white));
collapsingToolbarLayout.setExpandedTitleColor(getResources().getColor(R.color.white));
collapsingToolbarLayout.setExpandedTitleColor(Color.TRANSPARENT);
//设置纱布
collapsingToolbarLayout.setContentScrimColor((getResources().getColor(R.color.colorAccent)));
//监听appBarLayout的偏移
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if(Math.abs(verticalOffset) >= appBarLayout.getTotalScrollRange()){
toolbar.setTitleTextColor(getResources().getColor(R.color.white));
collapsingToolbarLayout.setTitle("AppbarLayout");
}else{
collapsingToolbarLayout.setTitle("");
}
}
});
}
}
CollapsingToolbarLayout
CollapsingToolbarLayout是一个折叠的Toolbar。
推荐CoordinatorLayout + AppBarLayout + CollapsingToolbarLayout一起使用
1.Collapsing title–>折叠标题
2.Content scrim–>内容纱布
3.Status bar scrim–>状态栏纱布
4.Parallax scrolling children–>有视差地滚动子View
5.Pinned position children–>固定子View的位置
四自定义的behavior
xml文件
<?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=".BehaviorActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="#00ffffff"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@mipmap/meizhi"
android:fitsSystemWindows="true"
android:scaleType="fitXY"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.7" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/scollView"
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="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="111"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="222"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="333"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="444"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="555"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="666"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="777"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
behaivor常用的方法详解
package com.dongnao.dn_vip_ui_15_2;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.widget.NestedScrollView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* BeHavior常用的方法详解
*/
public class MyBeHavior extends CoordinatorLayout.Behavior {
//列表顶部和textView之间的距离
private float deltaY;
public MyBeHavior(Context context, AttributeSet attributeSet){
super(context,attributeSet);
}
/**
* 表示是否给应用了Behavior 的View 指定一个观察的布局,通常,当观察的View 布局发生变化时
* 不管被观察View 的顺序怎样,被观察的View也会重新布局
* @param parent
* @param child 绑定behavior 的View 观察者
* @param dependency 被观察者的view
* @return 如果child 是观察者观察的View 返回true,否则返回false
*/
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof NestedScrollView;
}
/**
* 当被观察者的View 状态(如:位置、大小)发生变化时,这个方法被调用
* @param parent
* @param child
* @param dependency
* @return
*/
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
if(deltaY == 0){
deltaY = dependency.getY() - child.getHeight();
}
//被观察者View的Y坐标 - 观察者的高度 得到的就是两者之间的距离
float dy = dependency.getY() - child.getHeight();
//如果两者之间的距离小于0 就赋值为0 如果两者之间的距离不小于0 就将两者之间的实际距离赋值给它
dy = dy<0?0 : dy;
//计算Y轴每次偏移的距离
float y = -(dy/deltaY) * child.getHeight();
Log.e("BEHAVIOR----->",y+"-------------");
//将编译距离设置给观察者
child.setTranslationY(y);
return false;
}
/**
* 当coordinatorLayout 的子View试图开始嵌套滑动的时候被调用。当返回值为true的时候表明
* coordinatorLayout 充当nested scroll parent 处理这次滑动,需要注意的是只有当返回值为true
* 的时候,Behavior 才能收到后面的一些nested scroll 事件回调(如:onNestedPreScroll、onNestedScroll等)
* 这个方法有个重要的参数nestedScrollAxes,表明处理的滑动的方向。
*
* @param coordinatorLayout 和Behavior 绑定的View的父CoordinatorLayout
* @param child 和Behavior 绑定的View 观察者
* @param directTargetChild
* @param target
* @param nestedScrollAxes 嵌套滑动 应用的滑动方向
* @param type
*
* @return
*/
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild,
View target, int nestedScrollAxes, int type) {
child.setVisibility(View.GONE);
return false;
}
/**
* 嵌套滚动发生之前被调用
* 在nested scroll child 消费掉自己的滚动距离之前,嵌套滚动每次被nested scroll child
* 更新都会调用onNestedPreScroll。注意有个重要的参数consumed,可以修改这个数组表示你消费
* 了多少距离。假设用户滑动了100px,child 做了90px 的位移,你需要把 consumed[1]的值改成90,
* 这样coordinatorLayout就能知道只处理剩下的10px的滚动。
* @param coordinatorLayout
* @param child
* @param target
* @param dx 用户水平方向的滚动距离
* @param dy 用户竖直方向的滚动距离
* @param consumed
*/
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed, int type) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed,type);
}
/**
* 进行嵌套滚动时被调用
* @param coordinatorLayout
* @param child
* @param target
* @param dxConsumed target 已经消费的x方向的距离
* @param dyConsumed target 已经消费的y方向的距离
* @param dxUnconsumed x 方向剩下的滚动距离
* @param dyUnconsumed y 方向剩下的滚动距离
*/
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed,
int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,type);
}
/**
* 嵌套滚动结束时被调用,这是一个清除滚动状态等的好时机。
* @param coordinatorLayout
* @param child
* @param target
*/
@Override
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int type) {
super.onStopNestedScroll(coordinatorLayout, child, target,type);
}
/**
* onStartNestedScroll返回true才会触发这个方法,接受滚动处理后回调,可以在这个
* 方法里做一些准备工作,如一些状态的重置等。
* @param coordinatorLayout
* @param child
* @param directTargetChild
* @param target
* @param nestedScrollAxes
*/
@Override
public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, View child, View directTargetChild,
View target, int nestedScrollAxes,int type) {
super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes,type);
}
/**
* 用户松开手指并且会发生惯性动作之前调用,参数提供了速度信息,可以根据这些速度信息
* 决定最终状态,比如滚动Header,是让Header处于展开状态还是折叠状态。返回true 表
* 示消费了fling.
*
* @param coordinatorLayout
* @param child
* @param target
* @param velocityX x 方向的速度
* @param velocityY y 方向的速度
* @return
*/
@Override
public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, View child, View target,
float velocityX, float velocityY) {
return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
}
//可以重写这个方法对子View 进行重新布局
@Override
public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
return super.onLayoutChild(parent, child, layoutDirection);
}
/**
* 是否拦截触摸
* @param parent
* @param child
* @param ev
* @return
*/
@Override
public boolean onInterceptTouchEvent(@NonNull CoordinatorLayout parent, @NonNull View child, @NonNull MotionEvent ev) {
return super.onInterceptTouchEvent(parent, child, ev);
}
}