Android Study Material Design 十三 之CoordinatorLayout交互动画

来源:互联网 发布:淘宝限购一件怎么设置 编辑:程序博客网 时间:2024/06/16 16:45

LZ-Says:相处之道,在于彼此真心相待。有人甘愿做傻子,只是懒得计较这些琐事~

这里写图片描述


前言

情不知何起,一往情深~

随着MaterialDesign深入学习,不知道小伙伴们有多少已经应用到项目中了呢?

今天,我们来说下有关CoordinatorLayout如何实现交互动画。

实现前,我们先来看一组动画,之后想想不经过CoordingatorLayout,我们该如何实现?


效果查看

这里写图片描述


实现方式一

基于上图,我们先来简单分析下,如果要我们实现,我们该如何实现呢?

1. RecycleView监听滑动事件;2. 滑动事件中通过对用户滑动Y轴滑动偏移量进行动画开启和隐藏操作。

下面开始着手实现~

第一步: 放置布局

右下方按钮使用ImageButton实现,通过layer-list来实现高仿FloatingActionButton效果。

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.materialdesignstudy.coordinatorlayout.CoordinatorLayoutActivity">    <android.support.v7.widget.RecyclerView        android:id="@+id/id_rv"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:clipChildren="false"        android:clipToPadding="false"        android:padding="?attr/actionBarSize" />    <android.support.v7.widget.Toolbar        android:id="@+id/id_toolbar"        android:layout_width="match_parent"        android:layout_height="?attr/actionBarSize"        android:background="?attr/colorPrimary" />    <ImageButton        android:id="@+id/id_fab"        android:layout_width="58dp"        android:layout_height="58dp"        android:layout_alignParentBottom="true"        android:layout_alignParentRight="true"        android:layout_margin="16dp"        android:background="@drawable/fag_bg"        android:onClick="getUseBehavior"        android:src="@drawable/ic_love" /></RelativeLayout>

layer-list文件如下:

<?xml version="1.0" encoding="utf-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android">    <!-- 首层 -->    <item>        <shape android:shape="oval">            <solid android:color="#FF00" />        </shape>    </item>    <!-- 下面阴影色  -->    <item android:bottom="2dp">        <shape android:shape="oval">            <solid android:color="#999" />        </shape>    </item></layer-list>

第二步: 定义接口,控制动画显示与隐藏

public interface HideScrollListener {    void onHide();    void onShow();}

第三步: 定义滑动监听类

这块需要注意如下几点:

1. dy代表Y轴滑动偏移量,当dy值为正数时,代表向上滑动,反之则为向下滑动;2. 由于onScrolled事件在用户滑动时进行触发,所以避免多次无效调用需要增加标识位。

具体代码如下:

public class FabScrollListener extends RecyclerView.OnScrollListener {    // 滑动偏移量小于20 不考虑    private static final int THRESHOLD = 20;    // 滑动累加    private int mDistance = 0;    private HideScrollListener mHideScrollListener;    // 是否可见    private boolean mIsVisible = true;    public FabScrollListener(HideScrollListener hideScrollListener) {        this.mHideScrollListener = hideScrollListener;    }    @Override    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {        super.onScrolled(recyclerView, dx, dy);        // dy:Y轴方向滑动时偏移量        // dy 为正数时 代表向上滑动 反之 代表向下滑动        // 滑动偏移量大于设定值 并且 当前处于可见状态 隐藏        if (mDistance > THRESHOLD && mIsVisible) { // ToolBar 隐藏            mHideScrollListener.onHide();            mDistance = 0;            mIsVisible = false;        }        // 滑动偏移量小于-设定值 并且 当前处于不可见状态 显示        if (mDistance < -THRESHOLD && !mIsVisible) { // ToolBar显示            mHideScrollListener.onShow();            mDistance = 0;            mIsVisible = true;        }        if (mIsVisible && dy > 0 || (!mIsVisible && dy < 0)) {            mDistance += dy;        }    }}

第四步: 实例化 展示效果

到此步,几乎属于很nice操作了,实现接口,重写方法,调用属性动画,一气呵成~

代码如下:

public class CoordinatorLayoutActivity extends AppCompatActivity implements HideScrollListener {    private Toolbar mToolbar;    private RecyclerView mRecyclerView;    private ImageButton mFab;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_coordinator_layout);        initView();    }    private void initView() {        mRecyclerView = (RecyclerView) findViewById(R.id.id_rv);        mFab = (ImageButton) findViewById(R.id.id_fab);        mToolbar = (Toolbar) findViewById(R.id.id_toolbar);        setSupportActionBar(mToolbar);        setTitle("HLQ-Blog");        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));        mRecyclerView.addOnScrollListener(new FabScrollListener(this));        List<String> sList = new ArrayList<>();        for (int i = 0; i < 50; i++) {            sList.add("Hi Every One " + i);        }        FabRecycleAdapter adapter = new FabRecycleAdapter(sList);        mRecyclerView.setAdapter(adapter);    }    @Override    public void onHide() {        mToolbar.animate().translationY(-mToolbar.getHeight()).setInterpolator(new AccelerateInterpolator(30));        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mFab.getLayoutParams();        mFab.animate().translationY(mFab.getHeight() + params.bottomMargin)                .setInterpolator(new AccelerateInterpolator(3));    }    @Override    public void onShow() {        mToolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));        mFab.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));    }    public void getUseBehavior(View view) {        startActivity(new Intent(this, BehaviorActivity.class));    }}

注:

由于我们这里使用的是属性动画,所以各位老铁应用的同时别忘记做兼容(属性动画)。

效果就不运行了,各位老帖运行吧,源码会在文末放出。

—————————–本小段为本文重点部分——————————-


CoordinatorLayout以及Behavior简述

CoordinatorLayout,遵循Material Design效果,隶属于Design包下,其主要作用为:

作为一个容器,与子View进行交互。通俗来讲就是,可以通过检测用户操作去实现不同酷炫效果。

CoordinatorLayout可与多种方式进行搭配,而今天,我们主要是通过和Behavior配合,实现文首效果。

那么Behavior又是什么鬼呢?

Behavior(行为),也就是说这里面封装好了一些用户常用行为,我们通过对用户某些行为(操作)进行相应的逻辑or效果控制即可。

下面我们基于上一个代码进行改造 。


实现方式二

第一步: 修改布局

1. 将RelativeLayout替换为CoordinatorLayout;2. 将ImageButton替换为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"    tools:context="com.materialdesignstudy.coordinatorlayout.behavior.BehaviorActivity">    <android.support.v7.widget.RecyclerView        android:id="@+id/id_rv"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:clipChildren="false"        android:clipToPadding="false"        android:padding="?attr/actionBarSize" />    <android.support.v7.widget.Toolbar        android:id="@+id/id_toolbar"        android:layout_width="match_parent"        android:layout_height="?attr/actionBarSize"        android:background="?attr/colorPrimary" />    <android.support.design.widget.FloatingActionButton        android:id="@+id/id_fab"        android:layout_width="58dp"        android:layout_height="58dp"        android:layout_gravity="right|bottom"        android:layout_margin="16dp"        android:background="@drawable/fag_bg"        android:src="@drawable/ic_love"        app:layout_behavior="com.materialdesignstudy.coordinatorlayout.behavior.FabBehavior" /></android.support.design.widget.CoordinatorLayout>

第二步: 定义Behavior

public class FabBehavior extends FloatingActionButton.Behavior {    private boolean visible = true;//是否可见    public FabBehavior(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout,                                       FloatingActionButton child, View directTargetChild, View target,                                       int nestedScrollAxes) {        // 当观察的View(RecyclerView)发生滑动的开始的时候回调的        // nestedScrollAxes:滑动关联轴, 我们现在只关心垂直的滑动。        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild,                target, nestedScrollAxes);    }    @Override    public void onNestedScroll(CoordinatorLayout coordinatorLayout,                               FloatingActionButton child, View target, int dxConsumed,                               int dyConsumed, int dxUnconsumed, int dyUnconsumed) {        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,                dxUnconsumed, dyUnconsumed);        // 当观察的view滑动的时候回调的        //根据情况执行动画        if (dyConsumed > 0 && visible) {            //show            visible = false;            onHide(child);        } else if (dyConsumed < 0) {            //hide            visible = true;            onShow(child);        }    }    public void onHide(FloatingActionButton fab) {        ViewCompat.animate(fab).scaleX(0f).scaleY(0f).start();    }    public void onShow(FloatingActionButton fab) {        ViewCompat.animate(fab).scaleX(1f).scaleY(1f).start();    }}

这里需要大家务必关注一点如下:

如果通过app:layout_behavior去引用我们自定义的behavior,则自定义behavior里面务必添加构造,如下:    public FabBehavior(Context context, AttributeSet attrs) {    super(context, attrs);}  不然会抛出“Could not inflate Behavior subclass”异常~!!! 

第三步: 精简Activity代码

    private void initView() {        mRecyclerView = (RecyclerView) findViewById(R.id.id_rv);        mFab = (ImageButton) findViewById(R.id.id_fab);        mToolbar = (Toolbar) findViewById(R.id.id_toolbar);        setSupportActionBar(mToolbar);        setTitle("HLQ-Blog");        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));        List<String> sList = new ArrayList<>();        for (int i = 0; i < 50; i++) {            sList.add("Hi Every One " + i);        }        FabRecycleAdapter adapter = new FabRecycleAdapter(sList);        mRecyclerView.setAdapter(adapter);    }

哦了,伙计们,现在鼠标轻轻一点,运行查看效果~


GitHub查看地址

https://github.com/HLQ-Struggle/MaterialDesignStudy

赞赏

如果本文对各位老铁有所帮助,不妨赞助LZ喝点东西,一分也是爱~

这里写图片描述

阅读全文
0 0
原创粉丝点击