美文网首页
Android Material Design 自定义Beha

Android Material Design 自定义Beha

作者: 花椒人生 | 来源:发表于2018-03-28 15:20 被阅读0次

Android Material Design 自定义Behavior

1.效果

Untitled.gif

2. 效果实现

这里采用Behavior来实现这个效果

2.1 布局

这里采用 CoordinatorLayout+FloatingActionButton 来实现这个效果

<?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:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.Toolbar
        android:id="@+id/behavior_toolbar"
        app:title="知乎首页"
        app:titleTextColor="@color/colorAccent"
        app:layout_scrollFlags="scroll|enterAlways|snap"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</android.support.design.widget.AppBarLayout>


<android.support.v7.widget.RecyclerView
    android:id="@+id/behavior_recyclelistview"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</android.support.v7.widget.RecyclerView>

<android.support.design.widget.FloatingActionButton
    android:id="@+id/behavior_fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom|end"
    android:layout_marginBottom="70dp"
    android:layout_marginEnd="16dp"
    android:layout_marginRight="16dp"
    android:src="@mipmap/ic_launcher"
    app:layout_behavior="com.test.cmMaterialDesign.CMTanslationBehavior"
    app:layout_scrollFlags="scroll|enterAlways|snap" />

<LinearLayout
    android:id="@+id/bottom_tab_layout"
    android:layout_width="match_parent"
    android:layout_height="?actionBarSize"
    android:layout_alignParentBottom="true"
    android:background="@color/colorAccent"
    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:src="@mipmap/ic_launcher"
        android:layout_weight="1"/>

    <ImageView
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:src="@mipmap/ic_launcher"
        android:layout_weight="1"/>
</LinearLayout>

</android.support.design.widget.CoordinatorLayout>

CoordinatorLayout 他可以协调子View的交互动作。他的核心就是Behavior,
官方介绍:Interaction behavior plugin for child views of CoordinatorLayout. 作用于CoordinatorLayout的子View的交互行为插件。一个Behavior 实现了用户的一个或者多个交互行为,它们可能包括拖拽、滑动、快滑或者其他一些手势。

Behavior 是一个顶层抽象类,其他的一些具体行为的Behavior 都是继承自这个类。它提供了几个重要的方法:

layoutDependsOn
onDependentViewChanged
onStartNestedScroll
onNestedPreScroll
onNestedScroll
onStopNestedScroll
onNestedScrollAccepted
onNestedPreFling
onStartNestedScroll
onLayoutChild

/**
 * 表示是否给应用了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 进行重新布局
@Override
public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
    return super.onLayoutChild(parent, child, layoutDirection);
}
2.2 自定义 Behavior 实现 FloatingActionBar 的动画控制
  public class CMTanslationBehavior extends FloatingActionButton.Behavior {

private boolean isOut = false;

public CMTanslationBehavior(Context context, AttributeSet attrs){
    super(context, attrs);
}

//确定滚动方向
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
    return  nestedScrollAxes  == ViewCompat.SCROLL_AXIS_VERTICAL;
}

@Override
public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull FloatingActionButton child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
    super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
    Log.e("TAG","dyConsumed -> "+dyConsumed+" dyUnconsumed -> "+dyUnconsumed);
    if(dyConsumed > 0){
        if(!isOut){
            //向上滑动
            int translationY = ((CoordinatorLayout.LayoutParams) child.getLayoutParams()).bottomMargin + child.getMeasuredHeight();
            child.animate().translationY(translationY).setDuration(500).start();
            isOut = true;
        }
    }else{
        if(isOut){
            //向下滑动
            child.animate().translationY(0).setDuration(500).start();
            isOut = false;
        }
    }
}
}

相关文章

网友评论

      本文标题:Android Material Design 自定义Beha

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