自己实现floatactionbutton展开折叠功能
来源:互联网 发布:淘宝客一淘活动广场 编辑:程序博客网 时间:2024/05/17 06:53
之前总会见到那种功能,好比屏幕右下角有个按钮,点击之后向上弹出一系列菜单按钮,然后点击菜单按钮会实现自己的业务并且同时这些菜单会收起到左下角。github上面有个关于这个功能实现的库,但是最近自己想要实现这样的功能,其实实现这个功能最主要的就是动画的应用了。
我们看到的那种效果都是点击一个按钮之后,别的菜单按钮从其底部依次弹出,但是又不是绝对的一个接着一个的弹出,而是有一定的时差的,然后收回也是一样子的。
然后说下思路:有几个菜单肯定就是会有几张图片的,布局里面我用的是一个相对布局,然后预览时候是各自覆盖的,除了最初展示的那个菜单图片,别的被覆盖的图片的透明度都是0。当点击最初的展示的菜单图片时候,首先是每个图片沿着y轴向上运动一段距离到达指定位置,然后是alpha透明度从0变为1以及scale从0变为1;同样收回的时候是一个相反的过程,首先是各个item需要alpha从1变到0以及scale从1变到0,然后在沿着y轴运动一段距离返回至其初始位置。然后我们看下代码关键代码:
//view的弹出动画,首先是将view移动至其该所在的位置,其次是大小以及 透明度的变化了 private AnimatorSet doAnimOpenItem(View view, int index) { float distance = index * ITEM_DISTANCE; AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play( ObjectAnimator.ofFloat(view, "alpha", 0, 1)) .with(ObjectAnimator.ofFloat(view, "scaleX", 0f, 1)) .with(ObjectAnimator.ofFloat(view, "scaleY", 0f, 1)) .after(ObjectAnimator.ofFloat(view, "translationY", 0, distance)); //设置的延时时间恰好是在前一个动画执行结束前 后一个动画就开始执行,给人一种连贯的感觉 animatorSet.setStartDelay(index * 40); animatorSet.setDuration(50); return animatorSet; }这段代码每个view弹出动画执行的方法,其中的ITEM_DISTANCE是每个Item之间的距离,其中很关键的一点是我们设置的延时,即setStartDelay,如果不设置这个就不会有那种连贯的感觉,具体可以看效果。
//点击之后执行展开动画的方法 private void doAnimOpen() { //如果正在执行动画则返回 if (isAnimating) { return; } isAnimating = true; isOpen = true; AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether( doAnimOpenItem(activityFloatmenuBinding.startIv2, 1), doAnimOpenItem(activityFloatmenuBinding.startIv3, 2), doAnimOpenItem(activityFloatmenuBinding.startIv4, 3), doAnimOpenItem(activityFloatmenuBinding.startIv5, 4)); animatorSet.setInterpolator(new OvershootInterpolator()); animatorSet.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { //动画执行完毕将其置为false isAnimating = false; } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); animatorSet.start(); }调用这个方法目的是为了让每个view都开始执行展开动画,可以看到上面用的是playTogether的,就是每个动画都是同时开始的,这个时候我们给每个动画设置的延时就起作用了,每个动画开始的延迟时间是跟其所在的位置是有关的,位置越靠后延时越久。其实本来我这里是用的顺序执行的, 即playSequentially的,即每个动画顺序执行,但是那样看起来没有连贯性,所以改成了playTogether然后给每个Item的动画加上延迟实现了效果。上面有个boolean类型的isAnimating,它的作用就是防止用户连续点击那个初始展示的图片,然后动画一直执行,并且还会乱序。
//每个Item关闭时候执行的动画 private AnimatorSet doAnimCloseItem(View view, int index) { float distance = index * ITEM_DISTANCE; AnimatorSet animatorSet = new AnimatorSet(); //首先是将view大小变为0,以及透明度变为0,然后将其移动至原来的位置 animatorSet.play( ObjectAnimator.ofFloat(view, "alpha", 1, 0)) .with(ObjectAnimator.ofFloat(view, "scaleX", 1, 0f)) .with(ObjectAnimator.ofFloat(view, "scaleY", 1, 0f)) .before(ObjectAnimator.ofFloat(view, "translationY", distance, 0)); animatorSet.setDuration(50); //关闭时候恰好跟开始时候是相反的,所以延迟时间是越靠后越少了 animatorSet.setStartDelay((5 - index) * 40); return animatorSet; }这里唯一的不同就是先执行的Item透明度以及大小的动画然后执行的是移动的动画,因为每个Item都是同时执行的所以如果先移动的话会有重叠的情况,同样延时也是也是随着index的增大越来越小的了。
//所有Item执行关闭动画的方法 private void doAnimClose() { //如果正在执行动画则返回 if (isAnimating) { return; } isAnimating = true; isOpen = false; AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether( doAnimCloseItem(activityFloatmenuBinding.startIv5, 4), doAnimCloseItem(activityFloatmenuBinding.startIv4, 3), doAnimCloseItem(activityFloatmenuBinding.startIv3, 2), doAnimCloseItem(activityFloatmenuBinding.startIv2, 1)); animatorSet.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { //动画执行完毕将其置为false isAnimating = false; } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); animatorSet.start(); }最后这个方法是让每个view都执行折叠方法,跟让每个view都执行展开动画的差不多。
具体的代码就到这里了,其实就是属性动画的应用,代码已经上传github,可以点击这里查看。如果不对之处,欢迎批评指正。
阅读全文