前言
悬浮按钮是我非常喜欢的, 可以把最关键的功能放入到悬浮按钮中. 比如日记app里的新建日记, 阅读类app里的喜欢. 稍微处理一下可以将悬浮按钮扩展成悬浮菜单, 来看下实现吧! github直接看源码
废话不多说, 先看图, 感兴趣再往下看!
悬浮菜单
记得导包.
compile 'com.android.support:design:26.+'
配合Snackbar
Button btHide = (Button) findViewById(R.id.bt_hide);
btHide.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fab.hide();
}
});
Button btShow = (Button) findViewById(R.id.bt_show);
btShow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fab.show();
}
});
隐藏和显示
设置颜色
注意看颜色
android:layout_gravity="bottom|left"
设置位置
吸附效果如下, 即使滚动也会保持相对的位置:
app:layout_anchor="@id/toolbar"
app:layout_anchorGravity="center|bottom"
吸附并设置位置
来看看效果图是如何实现的吧.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<FrameLayout
android:id="@+id/fl_fan_menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginBottom="@dimen/twenty_dp"
android:layout_marginEnd="@dimen/twenty_dp"
android:src="@mipmap/ic_launcher"
app:backgroundTint="@color/colorAccent"
app:elevation="@dimen/zero_dp"
app:fabSize="mini" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_left_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginBottom="@dimen/twenty_dp"
android:layout_marginEnd="@dimen/twenty_dp"
android:src="@mipmap/ic_launcher"
app:backgroundTint="@color/colorAccent"
app:elevation="@dimen/zero_dp"
app:fabSize="mini" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginBottom="@dimen/twenty_dp"
android:layout_marginEnd="@dimen/twenty_dp"
android:src="@mipmap/ic_launcher"
app:backgroundTint="@color/colorAccent"
app:elevation="@dimen/zero_dp"
app:fabSize="mini" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_origin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginBottom="@dimen/twenty_dp"
android:layout_marginEnd="@dimen/twenty_dp"
android:src="@drawable/ic_add"
app:backgroundTint="@color/colorPrimary"
app:fabSize="normal" />
</FrameLayout>
<RelativeLayout
android:id="@+id/rl_line_menu"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/rl_menu_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<LinearLayout
android:id="@+id/ll_fun1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="@dimen/hundred_dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_toLeftOf="@+id/fab_mini1"
android:layout_weight="1"
android:gravity="right"
android:paddingRight="@dimen/eight_dp"
android:text="1"
android:textColor="@android:color/white"
android:textSize="@dimen/sixteen_sp" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_mini1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/twenty_six_dp"
android:src="@mipmap/ic_launcher"
app:backgroundTint="@color/colorPrimary"
app:fabSize="mini" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_fun2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/ll_fun1"
android:layout_marginBottom="@dimen/twenty_dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_toLeftOf="@+id/fab_mini2"
android:layout_weight="1"
android:gravity="right"
android:paddingRight="@dimen/eight_dp"
android:text="2"
android:textColor="@android:color/white"
android:textSize="@dimen/sixteen_sp" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_mini2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/twenty_six_dp"
android:src="@mipmap/ic_launcher"
app:backgroundTint="@color/colorPrimary"
app:fabSize="mini" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_fun3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/ll_fun2"
android:layout_marginBottom="@dimen/twenty_dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_toLeftOf="@+id/fab_mini2"
android:layout_weight="1"
android:gravity="right"
android:paddingRight="@dimen/eight_dp"
android:text="3"
android:textColor="@android:color/white"
android:textSize="@dimen/sixteen_sp" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_mini3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/twenty_six_dp"
android:src="@mipmap/ic_launcher"
app:backgroundTint="@color/colorPrimary"
app:fabSize="mini" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_fun4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/ll_fun3"
android:layout_marginBottom="@dimen/twenty_dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_toLeftOf="@+id/fab_mini2"
android:layout_weight="1"
android:gravity="right"
android:paddingRight="@dimen/eight_dp"
android:text="4"
android:textColor="@android:color/white"
android:textSize="@dimen/sixteen_sp" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_mini4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/twenty_six_dp"
android:src="@mipmap/ic_launcher"
app:backgroundTint="@color/colorPrimary"
app:fabSize="mini" />
</LinearLayout>
</RelativeLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="@dimen/twenty_dp"
android:layout_marginEnd="@dimen/twenty_dp"
android:backgroundTint="@color/colorAccent"
android:src="@drawable/ic_add"
app:fabSize="normal"
app:rippleColor="@color/colorPrimaryDark" />
</RelativeLayout>
<Button
android:id="@+id/bt_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/switch_menu" />
</RelativeLayout>
app:fabSize="mini"
就变成mini尺寸的了. 所以在设置动画和位置的时候不是将按钮全部放置在同一位置, 需要修正位置. 修正距离就是(normal-mini)/2, 应该很好理解.// 计算偏移值
int w = View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
int h = View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
mFabOrigin.measure(w, h);
mFabLeft.measure(w, h);
mOffset = (mFabOrigin.getMeasuredHeight() - mFabLeft.getMeasuredHeight()) / 2;
// 修正位置
FrameLayout.LayoutParams lParams = (FrameLayout.LayoutParams) mFabLeft.getLayoutParams();
lParams.setMargins(0, 0, UIUtil.dp2px(20) + mOffset, UIUtil.dp2px(20) + mOffset);
mFabLeft.setLayoutParams(lParams);
FrameLayout.LayoutParams ltParams = (FrameLayout.LayoutParams) mFabLeftTop.getLayoutParams();
ltParams.setMargins(0, 0, UIUtil.dp2px(20) + mOffset, UIUtil.dp2px(20) + mOffset);
mFabLeftTop.setLayoutParams(ltParams);
FrameLayout.LayoutParams tParams = (FrameLayout.LayoutParams) mFabTop.getLayoutParams();
tParams.setMargins(0, 0, UIUtil.dp2px(20) + mOffset, UIUtil.dp2px(20) + mOffset);
mFabTop.setLayoutParams(tParams);
/**
* 显示扇型菜单
*/
private void showFanMenu() {
// 标识符设置是
mFanMenuOpen = true;
// 按钮1向左移动
int x = (int) mFabOrigin.getX();
int y = (int) mFabOrigin.getY();
ValueAnimator va1 = ValueAnimator.ofInt(x, x - ConstantUtil.FAN_OFFSET);
va1.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int l = (int) animation.getAnimatedValue();
int t = (int) mFabLeft.getY();
int r = mFabLeft.getWidth() + l;
int b = mFabLeft.getHeight() + t;
mFabLeft.layout(l, t, r, b);
}
});
// 按钮2向左上移动
ValueAnimator va2x = ValueAnimator.ofInt(x, x - (int) (ConstantUtil.FAN_OFFSET / Math.pow(2, 1.0 / 2)));
ValueAnimator va2y = ValueAnimator.ofInt(y, y - (int) (ConstantUtil.FAN_OFFSET / Math.pow(2, 1.0 / 2)));
va2x.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int l = (int) animation.getAnimatedValue();
int t = (int) mFabLeftTop.getY();
int r = mFabLeftTop.getWidth() + l;
int b = mFabLeftTop.getHeight() + t;
mFabLeftTop.layout(l, t, r, b);
}
});
va2y.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int l = (int) mFabLeftTop.getX();
int t = (int) animation.getAnimatedValue();
int r = mFabLeftTop.getWidth() + l;
int b = mFabLeftTop.getHeight() + t;
mFabLeftTop.layout(l, t, r, b);
}
});
// 按钮3向上移动
ValueAnimator va3 = ValueAnimator.ofInt(y, y - ConstantUtil.FAN_OFFSET);
va3.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int l = (int) mFabTop.getX();
int t = (int) animation.getAnimatedValue();
int r = mFabTop.getWidth() + l;
int b = mFabTop.getHeight() + t;
mFabTop.layout(l, t, r, b);
}
});
// 开始动画
va1.start();
va2x.start();
va2y.start();
va3.start();
}
mFabAdd.setImageResource(mLineMenuOpen ? R.drawable.ic_add : R.drawable.ic_close);
我本人还是很喜欢google的material design的, 这个悬浮按钮也非常实用. 喜欢记得点赞或者关注我哦, 有意见或者建议评论区见~