1.概述
??Material Design從Android5.0開始引入的,是一種全新的設(shè)計語言(翻譯為“原材料設(shè)計”),其實是谷歌提倡的一種設(shè)計風(fēng)格岸蜗、理念、原則绊袋。最近發(fā)現(xiàn)現(xiàn)在很多 app 包括最早的知乎沒有使用了毕匀,今天再來回顧一下控件的簡單使用,效果非常簡單癌别,先上張圖皂岔。
????效果展示
????????????????
2.控件介紹
??2.1 CoordinatorLayout:用來協(xié)調(diào)子控件,結(jié)合AppBarLayout展姐,F(xiàn)loatingActionButton等使用
??2.2 SwipeRefreshLayout:提供的下拉刷新的效果躁垛,里面只能包一個子控件可以包任意控件RecyclerView,ScrollView 圾笨,ListView教馆。
??2.3 ToolBar:加強版的ActionBar
??2.4 TabLayout:導(dǎo)航書簽,可以結(jié)合ViewPager使用
app:tabIndicatorColor 導(dǎo)航書簽下方指示線的顏色
app:tabIndicatorHeight 指示線的高度
app:tabSelectedTextColor 導(dǎo)航書簽選中時的字體顏色
app:tabMode="fixed" 顯示模式
1:fixed 全部展示
2. scrollable 滑動展示
??2.5 CollapsingToolBarLayout:折疊布局擂达,結(jié)合ToolBar使用
android:minHeight 最小高度
app:layout_scrollFlags 模式
scroll 想滾動就必須設(shè)置這個土铺。
enterAlways 實現(xiàn)quick return效果, 當(dāng)向下移動時,立即顯示View(比如Toolbar)板鬓。
exitUntilCollapsed 向上滾動時收縮View悲敷,但可以固定Toolbar一直在上面。
enterAlwaysCollapsed 當(dāng)你的View已經(jīng)設(shè)置minHeight屬性又使用此標(biāo)志時俭令,你的View只能以最小高度進入后德,只有當(dāng)滾動視圖到達頂部時才擴大到完整高度。
app:contentScrim 當(dāng)完全CollapsingToolbarLayout折疊(收縮)后的背景顏色抄腔。
app:expandedTitleGravity Toolbar的title顯示位置
app:expandedTitleMargin 設(shè)置顯示位置設(shè)置Margin值
app:layout_collapseParallaxMultiplier視差因子 0-1之間
app:layout_collapseMode 視差模式
pin:· 固定模式
parallax: 折疊效果
??2.6 SnackBar:MD風(fēng)格的Toast瓢湃,底部彈出
??2.7 TextInputLayout:自帶錯誤提示的文本框
??等等蒲跨,不一一介紹了,今天只是簡單的使用勋又,想了解噪径,可以去官網(wǎng)查看
3.效果實現(xiàn)
??3.1 CoordinatorLayout 和 Behavior 介紹
????CoordinatorLayout是什么? 看一下官方的介紹:Interaction behavior plugin for child views of (子視圖的交互行為插件)
????Behavior 實現(xiàn)了用戶的一個或者多個交互行為藏雏,它們可能包括拖拽拷况、滑動、快滑或者其他一些手勢掘殴。Behavior 是一個頂層抽象類赚瘦,其他的一些具體行為的 Behavior 都是繼承自這個類。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
tools:context=".one_18.BehaviorActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@color/blue"
app:layout_scrollFlags="scroll|enterAlways|snap"/>
<!-- <androidx.appcompat.widget.Toolbar-->
<!-- android:id="@+id/tool_bar"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- app:title="知乎首頁"-->
<!-- app:titleTextColor="#ffffff"-->
<!-- app:layout_scrollFlags="scroll|enterAlways|snap">-->
<!-- </androidx.appcompat.widget.Toolbar>-->
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginBottom="70dp"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
app:layout_behavior=".one_18.TranslationBehavior"
android:src="@mipmap/ic_launcher">
</com.google.android.material.floatingactionbutton.FloatingActionButton>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:background="@android:color/white"
app:layout_behavior="@string/bottom_sheet_behavior">
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@mipmap/ic_launcher"/>
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@mipmap/ic_launcher"/>
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@mipmap/ic_launcher"/>
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@mipmap/ic_launcher"/>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>
看一下Behaviror的方法作用
/**
* 表示是否給應(yīng)用了Behavior 的View 指定一個依賴的布局奏寨,通常起意,當(dāng)依賴的View 布局發(fā)生變化時
* 不管被被依賴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 super.layoutDependsOn(parent, child, dependency);
}
/**
* 當(dāng)被依賴的View 狀態(tài)(如:位置病瞳、大欣抗尽)發(fā)生變化時,這個方法被調(diào)用
* @param parent
* @param child
* @param dependency
* @return
*/
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
return super.onDependentViewChanged(parent, child, dependency);
}
/**
* 當(dāng)coordinatorLayout 的子View試圖開始嵌套滑動的時候被調(diào)用套菜。當(dāng)返回值為true的時候表明
* coordinatorLayout 充當(dāng)nested scroll parent 處理這次滑動亲善,需要注意的是只有當(dāng)返回值為true
* 的時候,Behavior 才能收到后面的一些nested scroll 事件回調(diào)(如:onNestedPreScroll逗柴、onNestedScroll等)
* 這個方法有個重要的參數(shù)nestedScrollAxes蛹头,表明處理的滑動的方向。
*
* @param coordinatorLayout 和Behavior 綁定的View的父CoordinatorLayout
* @param child 和Behavior 綁定的View
* @param directTargetChild
* @param target
* @param nestedScrollAxes 嵌套滑動 應(yīng)用的滑動方向戏溺,看 {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},
* {@link ViewCompat#SCROLL_AXIS_VERTICAL}
* @return
*/
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
}
/**
* 嵌套滾動發(fā)生之前被調(diào)用
* 在nested scroll child 消費掉自己的滾動距離之前渣蜗,嵌套滾動每次被nested scroll child
* 更新都會調(diào)用onNestedPreScroll。注意有個重要的參數(shù)consumed旷祸,可以修改這個數(shù)組表示你消費
* 了多少距離耕拷。假設(shè)用戶滑動了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) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
}
/**
* 進行嵌套滾動時被調(diào)用
* @param coordinatorLayout
* @param child
* @param target
* @param dxConsumed target 已經(jīng)消費的x方向的距離
* @param dyConsumed target 已經(jīng)消費的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) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
}
/**
* 嵌套滾動結(jié)束時被調(diào)用,這是一個清除滾動狀態(tài)等的好時機嫌吠。
* @param coordinatorLayout
* @param child
* @param target
*/
@Override
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {
super.onStopNestedScroll(coordinatorLayout, child, target);
}
/**
* onStartNestedScroll返回true才會觸發(fā)這個方法止潘,接受滾動處理后回調(diào),可以在這個
* 方法里做一些準(zhǔn)備工作辫诅,如一些狀態(tài)的重置等凭戴。
* @param coordinatorLayout
* @param child
* @param directTargetChild
* @param target
* @param nestedScrollAxes
*/
@Override
public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
}
/**
* 用戶松開手指并且會發(fā)生慣性動作之前調(diào)用,參數(shù)提供了速度信息炕矮,可以根據(jù)這些速度信息
* 決定最終狀態(tài)么夫,比如滾動Header者冤,是讓Header處于展開狀態(tài)還是折疊狀態(tài)。返回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 的時候調(diào)用档痪,可以重寫這個方法對子View 進行重新布局
*/
@Override
public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
return super.onLayoutChild(parent, child, layoutDirection);
}
??3.2 自定義 Behavior 來實現(xiàn) FloatingActionBar 的改變
public class TranslationBehavior<T extends FloatingActionButton> extends CoordinatorLayout.Behavior<T> {
private static final String TAG = "TranslationBehavior";
/**
* FloatingActionButton當(dāng)前是否是顯示狀態(tài)
*/
private boolean isOut = false;
public TranslationBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* 注意:當(dāng)coordinatorLayout 的子View試圖開始嵌套滑動的時候被調(diào)用涉枫。當(dāng)返回值為true的時候表明
* coordinatorLayout 充當(dāng)nested scroll parent 處理這次滑動,需要注意的是只有當(dāng)返回值為true
* 的時候腐螟,Behavior 才能收到后面的一些nested scroll 事件回調(diào)(如:onNestedPreScroll愿汰、onNestedScroll等)
* 這個方法有個重要的參數(shù)nestedScrollAxes,表明處理的滑動的方向乐纸。
* @param coordinatorLayout 和Behavior 綁定的View的父CoordinatorLayout
* @param child 和Behavior 綁定的View
* @param directTargetChild
* @param target
* @param axes 嵌套滑動,滑動方向衬廷, {@link ViewCompat#SCROLL_AXIS_HORIZONTAL}
* {@link ViewCompat#SCROLL_AXIS_VERTICAL}
* @return
*/
@Override
public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull T child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
Log.e(TAG,"onStartNestedScroll");
return axes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
/**
* 進行嵌套滾動時被調(diào)用
* @param coordinatorLayout
* @param child
* @param target
* @param dxConsumed target 已經(jīng)消費的x方向的距離
* @param dyConsumed target 已經(jīng)消費的y方向的距離 往上滑是正 往下滑是負(fù)
* @param dxUnconsumed x 方向剩下的滾動距離
* @param dyUnconsumed y 方向剩下的滾動距離
* @param type
*/
@Override
public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull T child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
Log.e(TAG,"onNestedScroll");
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
Log.e(TAG,"dyConsumed:"+dyConsumed+"--------dyUnconsumed:"+dyUnconsumed);
//1.將我們的child(FloatingActionButton)進行隱藏
if (dyConsumed > 0){
if (!isOut){
//2.移動距離計算 bottomMargin + 自己的高度
int translationY = ((CoordinatorLayout.LayoutParams)child.getLayoutParams()).bottomMargin + child.getMeasuredHeight();
child.animate().translationY(translationY).setDuration(500).start();
//3.注意:這樣設(shè)置后網(wǎng)上滑的時候會發(fā)現(xiàn)FloatingActionButton會反應(yīng)慢,我們可以設(shè)置一個標(biāo)志位
isOut = true;
}
}else {
if (isOut){
child.animate().translationY(0).setDuration(500).start();
isOut = false;
}
}
}
}