王学岗高级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);
    }
}

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