美文网首页Android技术知识Android开发Android开发经验谈
动画必须有(二):悬浮菜单了解一下!

动画必须有(二):悬浮菜单了解一下!

作者: sean_depp | 来源:发表于2018-07-27 16:17 被阅读26次

    动画必须有(一): 属性动画浅谈
    githhub传送门


    目录

    • 前言
    • 效果图
    • FloatingActionButton基础
    • FloatingActionButton实例
    • 最后

    前言

    悬浮按钮是我非常喜欢的, 可以把最关键的功能放入到悬浮按钮中. 比如日记app里的新建日记, 阅读类app里的喜欢. 稍微处理一下可以将悬浮按钮扩展成悬浮菜单, 来看下实现吧! github直接看源码


    效果图

    废话不多说, 先看图, 感兴趣再往下看!

    悬浮菜单

    FloatingActionButton基础

    记得导包.

    compile 'com.android.support:design:26.+'
    

    可以看看谷歌官方介绍. 你会被瞬间圈粉. 然后是官方文档, 这个文档说了如何调用.

    • 搭配Snackbar
      官方推荐配合Snackbar来使用, 这都不多说了.
    配合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();
        }
    });
    
    隐藏和显示
    • 颜色
      可以设置点击颜色app:rippleColor, 以及背景颜色app:backgroundTint. 我将背景色改成蓝色, 点击水波纹扩散变为紫色, 效果图如下:
    设置颜色 注意看颜色
    • 位置
      当然了, 位置可以随便改, 甚至可以吸附在某个控件之上.
    android:layout_gravity="bottom|left"
    
    设置位置

    吸附效果如下, 即使滚动也会保持相对的位置:

    app:layout_anchor="@id/toolbar"
    app:layout_anchorGravity="center|bottom"
    
    吸附并设置位置

    FloatingActionButton实例

    来看看效果图是如何实现的吧.

    • 布局文件
      布局文件是个要点, 里面塞进了两个菜单, 你选一个喜欢的用就好. 一个是扇型的, 一个是线型的.
    <?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>
    
    • normal与mini
      悬浮按钮有两种尺寸, normal和mini. 在xml中加入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);
    
    • 关于动画
      只要位置算对了, 动画不是特别难, 当然想要像google或者apple的动画那样舒适还是很难的. 没看第一篇的可以回头看看.
    /**
     * 显示扇型菜单
     */
    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();
    }
    
    • 切换图标
      然后就是在不同状态切换悬浮按钮的图标, 使用setImageResource方法即可.
    mFabAdd.setImageResource(mLineMenuOpen ? R.drawable.ic_add : R.drawable.ic_close);
    

    最后

    我本人还是很喜欢google的material design的, 这个悬浮按钮也非常实用. 喜欢记得点赞或者关注我哦, 有意见或者建议评论区见~

    动画必须有(一): 属性动画浅谈
    githhub传送门


    相关文章

      网友评论

        本文标题:动画必须有(二):悬浮菜单了解一下!

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