王學崗高級UI14——————MaterialDesign中常用控件詳解和超酷炫的組合使用以及嵌套滑動

第一ToolBar

這個就省略了,網上關於他的資料太多了

第二AppbarLayout

默認是一個垂直的LinearLayout。
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);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章