Android实现炫酷的底部菜单栏切换动画效果

最近按照需求做了一个花里胡哨的首页底部菜单切换,我不会做GIF,传两张图看一下效果

 

点击不同的位置,底部Bar的凹陷位置会移动,同事选中的图标会上升,非选中的图标会下降,同时,图标的背景圆圈会做东升西落的动画效果。

实现原理:这个效果其实可以分解为三个动画,1、底部凹陷位置的移动。2、图标的上升与下降。3、背景圆圈的东升西落

图标上升下降的代码和背景运动的代码如下

private void iconUpAnim(ImageView ivIcon) {
        initLocation(ivIcon);
        llyCircleAnim.addView(waterDropNewItem.getImageView());//把动画图片添加到动画

        //抛物线动画,原理:两个位移动画,一个横向匀速移动,一个纵向变速移动,两个动画同时执行,就有了抛物线的效果。
        ObjectAnimator translateAnimationX = ObjectAnimator.ofFloat(waterDropNewItem.getImageView(), "translationX", 0, waterDropNewItem.getTranslationUpX());
        translateAnimationX.setInterpolator(new AccelerateInterpolator());

        ObjectAnimator translateAnimationY = ObjectAnimator.ofFloat(waterDropNewItem.getImageView(), "translationY", 0, waterDropNewItem.getTranslationUpY());
        translateAnimationY.setInterpolator(new LinearInterpolator());

        translateAnimationY.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                waterDropOldItem = new WaterDropItem();
                waterDropOldItem.copy(waterDropNewItem);
            }

            @Override
            public void onAnimationCancel(Animator animation) {
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }
        });

        ObjectAnimator translationX = new ObjectAnimator().ofFloat(ivIcon, "translationX", 0, 0);
        ObjectAnimator translationY = new ObjectAnimator().ofFloat(ivIcon, "translationY", 0, -waterDropAnimUpDistance);

        AnimatorSet animatorSet = new AnimatorSet();  //组合动画
        animatorSet.playTogether(translationX, translationY, translateAnimationX, translateAnimationY); //设置动画
        animatorSet.setDuration(800);  //设置动画时间
        animatorSet.start(); //启动
    }

    private void iconDownAnim(ImageView ivIcon) {
//抛物线动画,原理:两个位移动画,一个横向匀速移动,一个纵向变速移动,两个动画同时执行,就有了抛物线的效果。
        ObjectAnimator translateAnimationX = ObjectAnimator.ofFloat(waterDropOldItem.getImageView(), "translationX", waterDropOldItem.getTranslationUpX(), waterDropOldItem.getTranslationDownX());
        translateAnimationX.setInterpolator(new LinearInterpolator());

        ObjectAnimator translateAnimationY = ObjectAnimator.ofFloat(waterDropOldItem.getImageView(), "translationY", waterDropOldItem.getTranslationUpY(), waterDropOldItem.getTranslationDownY());
        translateAnimationY.setInterpolator(new AccelerateInterpolator());


        translateAnimationY.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                waterDropOldItem.finish();
//                llyCircleAnim.removeView(waterDropOldItem.getImageView()); //动画结束后移除动画图片
                llyCircleAnim.removeViewAt(0);
            }

            @Override
            public void onAnimationCancel(Animator animation) {
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }
        });

        ObjectAnimator translationX = new ObjectAnimator().ofFloat(ivIcon, "translationX", 0, 0);
        ObjectAnimator translationY = new ObjectAnimator().ofFloat(ivIcon, "translationY", -waterDropAnimUpDistance, 0f);

        AnimatorSet animatorSet = new AnimatorSet();  //组合动画
//        animatorSet.playTogether(translationX, translationY); //设置动画
        animatorSet.playTogether(translationX, translationY, translateAnimationX, translateAnimationY); //设置动画
        animatorSet.setDuration(800);  //设置动画时间
        animatorSet.start(); //启动
    }

凹陷位置的移动代码不是动画,是自定义VIew通过不断的重绘完成的

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 从canvas层面去除锯齿
        canvas.setDrawFilter(mDrawFilter);
        canvas.drawColor(Color.TRANSPARENT);

        /*
         * 将绘制操作保存到新的图层
         */
        int sc = canvas.saveLayer(0, 0, mTotalWidth, mTotalHeight, null, Canvas.ALL_SAVE_FLAG);

        // 设定要绘制的部分
        mSrcRect.set(mCurrentImgLeft, 0, mCurrentImgLeft + screenWidth, mTotalHeight);
        // 绘纹部分
        canvas.drawBitmap(mSrcBitmap, mSrcRect, mDestRect, mBitmapPaint);

        // 设置图像的混合模式
        mBitmapPaint.setXfermode(mPorterDuffXfermode);
        mBitmapPaint.setXfermode(null);
        canvas.restoreToCount(sc);
    }


    // 初始化画笔paint
    private void initPaint() {
        mBitmapPaint = new Paint();
        // 防抖动
        mBitmapPaint.setDither(true);
        // 开启图像过滤
        mBitmapPaint.setFilterBitmap(true);
        mPicPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPicPaint.setDither(true);
        mPicPaint.setColor(Color.RED);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mTotalWidth = w;
        mTotalHeight = h;

        mSrcRect = new Rect();
        mDestRect = new Rect(0, 0, mTotalWidth, mTotalHeight);
    }

    public void setPosition(int position) {
        if (isSliding) {
            return;
        }
        isSliding = true;

        final int targetImgLeft = mStartImgLeft - itemHalfWidth * position * 2;
        int a = Math.abs(targetImgLeft - mCurrentImgLeft) / (itemHalfWidth - 1) - 1;
        if (a <= 0) {
            isSliding = false;
            return;
        }
//        mSpeed = a * mSpeed;//根据距离大小改变速度
        new Thread() {
            public void run() {
                while (true) {
                    if (targetImgLeft < mCurrentImgLeft) {
                        //向右
                        mCurrentImgLeft -= mSpeed;
                    } else if (targetImgLeft > mCurrentImgLeft) {
                        //向左
                        mCurrentImgLeft += mSpeed;
                    } else {
                        //不变
                        return;
                    }
                    try {
                        // 为了保证效果的同时,尽可能将cpu空出来,供其他部分使用
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                    }

                    if (Math.abs(mCurrentImgLeft - targetImgLeft) <= mSpeed) {
//                        动画停止
                        mSpeed = 40;
                        mCurrentImgLeft = targetImgLeft;
                        isSliding = false;
                        postInvalidate();
                        return;
                    }
                    postInvalidate();
                }

            }
        }.start();
    }

完整DEMO

https://download.csdn.net/download/y280903468/11972944

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值