Android Study Material Design 十三 之CoordinatorLayout交互动画
程序员文章站
2022-05-30 22:17:47
...
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查看地址
赞赏
如果本文对各位老铁有所帮助,不妨赞助LZ喝点东西,一分也是爱~
推荐阅读
-
Android Study Material Design 十三 之CoordinatorLayout交互动画
-
Android Study Material Design 九 之 Hello TabLayout
-
Android Study Material Design 十二 之 FloatingActionButton初识
-
Android Study Material Design 五 番外篇 之:深入分析SnackBar源码
-
Android Study Material Design 十七 之 转场动画
-
Android Study Material Design 八 之 玩转Palette调色板
-
Android Study Material Design 七 之 谈谈ToolBar以及SearchView
-
Android Study Material Design 二 之:这可能是RecyclerView最全解析 初级使用(一)
-
Android Study Material Design 六 之:TextInputLayout学习及分析部分源码