FloatingActionButton
一个基本的使用例子如下:
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="right|bottom"
android:onClick="rotate"
android:src="@drawable/ic_add_white_24dp"
app:backgroundTint="?attr/colorPrimary"
app:elevation="10dp"
app:fabSize="normal"
app:rippleColor="#f00"
/>
其中:
- src属性是设置图标
- backgroundTint是设置背景色(图标是透明背景的)
- elevation是设置阴影大小
- fabsize是设置图标的大小,一般为normal(不用设置)
- rippleColor是设置水波纹的颜色
点击事件如下(旋转):
private boolean reverse = false;
public void rotate(View v) {
float toDegree = reverse ? -180f : 180f;
ObjectAnimator animator = ObjectAnimator
.ofFloat(v, "rotation", 0.0f, toDegree)
.setDuration(400);
animator.start();
reverse = !reverse;
}
兼容性问题
与CardViewy一样:
阴影的细微差别,这里直接在不同的dimen中设置即可:
- 5.x系统:边距阴影比较小,需要手动添加边距16dp,android:layout_margin="16dp"
- 4.x系统:边距阴影比较大,手动修改边距0dp(原因:兼容包里面设置阴影效果自动设置了margin来处理16dp)
FloatingActionButton动画
列表滑动的时候FloatingActionButton隐藏与显示
通过自定义OnScrollListener实现
核心的逻辑如下:
public class FabScrollListener extends OnScrollListener {
private static final int THRESHOLD = 20;
private int distance = 0;
private HideScrollListener hideListener;
private boolean visible = true;//是否可见
public FabScrollListener(HideScrollListener hideScrollListener) {
this.hideListener = hideScrollListener;
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
/**
* dy:Y轴方向的增量
* 有正和负
* 当正在执行动画的时候,就不要再执行了
*/
if (distance > THRESHOLD && visible) {
//隐藏动画
visible = false;
hideListener.onHide();
distance = 0;
} else if (distance < -THRESHOLD && !visible) {
//显示动画
visible = true;
hideListener.onShow();
distance = 0;
}
if (visible && dy > 0 || (!visible && dy < 0)) {
distance += dy;
}
}
}
自定义一个OnScrollListener,重写onScrolled方法。判断当前的滚动方向、滚动距离、当前的FloatingActionButton是否显示来进行相应的逻辑处理。
其中HideScrollListener是一个自定义的监听接口:
public interface HideScrollListener {
void onHide();
void onShow();
}
由Activity实现这个接口:
public class FabAnimActivity extends AppCompatActivity implements HideScrollListener {
private RecyclerView recyclerview;
private ImageButton fab;
private Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//省略一些代码
//添加滑动监听
recyclerview.addOnScrollListener(new FabScrollListener(this));
}
@Override
public void onHide() {
// 隐藏动画--属性动画
toolbar.animate().translationY(-toolbar.getHeight()).setInterpolator(new AccelerateInterpolator(3));
RelativeLayout.LayoutParams layoutParams = (LayoutParams) fab.getLayoutParams();
fab.animate().translationY(fab.getHeight() + layoutParams.bottomMargin).setInterpolator(new AccelerateInterpolator(3));
}
@Override
public void onShow() {
// 显示动画--属性动画
toolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));
fab.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));
}
}
通过自定义FloatingActionButton的Behavior实现
通过协调并调度里面的子控件或者布局来实现触摸(一般是指滑动)产生一些相关的动画效果。可以通过设置view的Behavior来实现触摸的动画调度。
继承FloatingActionButton的Behavior:
public class FabBehavior extends FloatingActionButton.Behavior {
private boolean visible = true;//是否可见
//实例化CoordinatorLayout.LayoutParams时反射生成Behavior实例,这就是为什么自定义behavior需要重写如下的构造函数
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) {
// 隐藏动画--属性动画
// toolbar.animate().translationY(-toolbar.getHeight()).setInterpolator(new AccelerateInterpolator(3));
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
// fab.animate().translationY(fab.getHeight()+layoutParams.bottomMargin).setInterpolator(new AccelerateInterpolator(3));
//FAB 缩小
ViewCompat.animate(fab).scaleX(0f).scaleY(0f).start();
}
public void onShow(FloatingActionButton fab) {
// 显示动画--属性动画
// toolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
// fab.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));
//FAB放大
ViewCompat.animate(fab).scaleX(1f).scaleY(1f).start();
}
}
其中:
构造方法必须重写,重写onStartNestedScroll返回判断哪个方向的滑动,重写onNestedScroll进行相应的逻辑处理(FloatingActionButton的属性动画显示与隐藏)。
最后在布局文件中使用CoordinatorLayout布局,并且给FloatingActionButton添加自定义的Behavior:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingTop="?attr/actionBarSize"
/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:title="Fab动画"
app:titleTextColor="#fff"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="58dp"
android:layout_height="58dp"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@drawable/ic_favorite_outline_white_24dp"
app:layout_behavior="com.nan.advancedui.fab.anim.behavior.FabBehavior"
/>
</android.support.design.widget.CoordinatorLayout>
如果觉得我的文字对你有所帮助的话,欢迎关注我的公众号:
我的群欢迎大家进来探讨各种技术与非技术的话题,有兴趣的朋友们加我私人微信huannan88,我拉你进群交(♂)流(♀)。