第一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);
}
}