欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-24 21:02:05
...

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

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

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

 

点击不同的位置,底部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