美文网首页view
MD - 简单控件使用以及自定义Behavior

MD - 简单控件使用以及自定义Behavior

作者: 如愿以偿丶 | 来源:发表于2019-09-29 21:35 被阅读0次

    1.概述

      Material Design从Android5.0开始引入的,是一种全新的设计语言(翻译为“原材料设计”),其实是谷歌提倡的一种设计风格、理念、原则。最近发现现在很多 app 包括最早的知乎没有使用了,今天再来回顾一下控件的简单使用,效果非常简单,先上张图。

        效果展示
                    

    在这里插入图片描述

    2.控件介绍

      2.1 CoordinatorLayout:用来协调子控件,结合AppBarLayout,FloatingActionButton等使用
      2.2 SwipeRefreshLayout:提供的下拉刷新的效果,里面只能包一个子控件可以包任意控件RecyclerView,ScrollView ,ListView。
      2.3 ToolBar:加强版的ActionBar
      2.4 TabLayout:导航书签,可以结合ViewPager使用
            app:tabIndicatorColor            导航书签下方指示线的颜色
            app:tabIndicatorHeight           指示线的高度
            app:tabSelectedTextColor         导航书签选中时的字体颜色
            app:tabMode="fixed"              显示模式
                        1:fixed             全部展示
                        2. scrollable        滑动展示
    
      2.5 CollapsingToolBarLayout:折叠布局,结合ToolBar使用
            android:minHeight                    最小高度
            app:layout_scrollFlags               模式
                        scroll                   想滚动就必须设置这个。
                        enterAlways              实现quick return效果, 当向下移动时,立即显示View(比如Toolbar)。
                        exitUntilCollapsed       向上滚动时收缩View,但可以固定Toolbar一直在上面。
                        enterAlwaysCollapsed     当你的View已经设置minHeight属性又使用此标志时,你的View只能以最小高度进入,只有当滚动视图到达顶部时才扩大到完整高度。
            app:contentScrim                     当完全CollapsingToolbarLayout折叠(收缩)后的背景颜色。
            app:expandedTitleGravity             Toolbar的title显示位置
            app:expandedTitleMargin              设置显示位置设置Margin值
            app:layout_collapseParallaxMultiplier视差因子   0-1之间
            app:layout_collapseMode              视差模式
                        pin:·                    固定模式
                        parallax:                折叠效果
    
      2.6 SnackBar:MD风格的Toast,底部弹出
      2.7 TextInputLayout:自带错误提示的文本框

      等等,不一一介绍了,今天只是简单的使用,想了解,可以去官网查看

    3.效果实现

      3.1 CoordinatorLayout 和 Behavior 介绍

        CoordinatorLayout是什么? 看一下官方的介绍:Interaction behavior plugin for child views of (子视图的交互行为插件)
        Behavior 实现了用户的一个或者多个交互行为,它们可能包括拖拽、滑动、快滑或者其他一些手势。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的方法作用

     /**
         * 表示是否给应用了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 super.layoutDependsOn(parent, child, dependency);
        }
    
        /**
         * 当被依赖的View 状态(如:位置、大小)发生变化时,这个方法被调用
         * @param parent
         * @param child
         * @param dependency
         * @return
         */
        @Override
        public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
            return super.onDependentViewChanged(parent, child, dependency);
        }
    
        /**
         *  当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 嵌套滑动 应用的滑动方向,看 {@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);
        }
    
        /**
         * 嵌套滚动发生之前被调用
         * 在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) {
            super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
        }
    
        /**
         * 进行嵌套滚动时被调用
         * @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) {
            super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        }
    
        /**
         *  嵌套滚动结束时被调用,这是一个清除滚动状态等的好时机。
         * @param coordinatorLayout
         * @param child
         * @param target
         */
        @Override
        public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {
            super.onStopNestedScroll(coordinatorLayout, child, target);
        }
    
        /**
         * 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) {
            super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
        }
    
        /**
         * 用户松开手指并且会发生惯性动作之前调用,参数提供了速度信息,可以根据这些速度信息
         * 决定最终状态,比如滚动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 的时候调用,可以重写这个方法对子View 进行重新布局
         */
        @Override
        public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
            return super.onLayoutChild(parent, child, layoutDirection);
        }
    
      3.2 自定义 Behavior 来实现 FloatingActionBar 的改变
        public class TranslationBehavior<T extends FloatingActionButton> extends CoordinatorLayout.Behavior<T> {
            private static final String TAG = "TranslationBehavior";
            
            /**
             * FloatingActionButton当前是否是显示状态
             */
            private boolean isOut = false;
        
            public TranslationBehavior(Context context, AttributeSet attrs) {
                super(context, attrs);
            }
        
            /**
             *  注意:当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 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;
            }
        
        
            /**
             * 进行嵌套滚动时被调用
             * @param coordinatorLayout
             * @param child
             * @param target
             * @param dxConsumed    target 已经消费的x方向的距离
             * @param dyConsumed    target 已经消费的y方向的距离  往上滑是正  往下滑是负
             * @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.注意:这样设置后网上滑的时候会发现FloatingActionButton会反应慢,我们可以设置一个标志位
                        isOut = true;
                    }
                }else {
                    if (isOut){
                        child.animate().translationY(0).setDuration(500).start();
                        isOut = false;
                    }
                }
            }
        }
    

    相关文章

      网友评论

        本文标题:MD - 简单控件使用以及自定义Behavior

        本文链接:https://www.haomeiwen.com/subject/yhmqpctx.html