美文网首页Android进阶之旅安卓资源收集
自定义View-雪花和下雪动画

自定义View-雪花和下雪动画

作者: xandone | 来源:发表于2017-02-21 09:13 被阅读870次

    一、武汉每年都会下一场雪,然而今年却没有,雪花还是很漂亮的,据说雪花的形状有几十种,雪花图:


    Paste_Image.png

    大自然鬼斧神工啊。
    二、前几天看到有人写了一个关于“下雪”的自定义View,很有意思,但是感觉雪花写得不是很满意,是用椭圆代替的,虽说现实中观看的确是一坨坨的,但是我还是想从细腻的角度去描绘一番(下图为代码所写)。
    先上个图看效果吧:


    a.gif
    雪花高清图:
    b.png

    三、绘制过程
    1.难点在于绘制当前这个雪花,我把它进行了分割,简化处理:
    分为四个部分,六边形部分:


    Paste_Image.png
    边刺部分:
    Paste_Image.png
    角刺主干和角刺部分:
    Paste_Image.png
    2.绘制过程中将坐标原点转换至视图中心位置,以该view中心点为坐标原点,方便坐标的计算。
    3.绘制正六边形:
    初始化六边形边长length,先绘制最上的一条边,然后旋转画布60°,分别绘制其余5边,具体如下:
        public void drawHexagon(Canvas canvas) {
            mPaint.setColor(Color.WHITE);
            mPaint.setStyle(Paint.Style.FILL);
            int x1 = -mLength / 2;
            int y1 = -(int) (Math.sqrt(3) * mLength / 2);
            int x2 = 0;
            int y2 = y1;
            canvas.save();
            for (int i = 0; i < 6; i++) {
                mPaint.setStrokeWidth(6);
                canvas.drawLine(x1, y1, x1 + mLength, y1, mPaint);
                mPaint.setStrokeWidth(2);
                canvas.drawLine(x2, y2, 0, 0, mPaint);
                canvas.rotate(60, 0, 0);
            }
            canvas.restore();
        }
    

    4.绘制边刺:
    该边刺为不规则图形,只能用path进行绘制,主要在于需确定好坐偏移量和上偏移量的坐标点位置,绘制一个后,同样对画布进行旋转60°,绘制其余5条:

        public void drawThorn(Canvas canvas) {
            mPaint.setColor(Color.WHITE);
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setStrokeWidth(2);
            int y = -(int) (Math.sqrt(3) * mLength / 2);
            mHexagonPath_1.moveTo(0 - mThornPadding_1, y);
            mHexagonPath_1.lineTo(0 - mThornPadding_1 - mThornPadding_2, y - mThornHeight_1);
            mHexagonPath_1.lineTo(0, y - mThornHeight_2);
            mHexagonPath_1.lineTo(0 + mThornPadding_1 + mThornPadding_2, y - mThornHeight_1);
            mHexagonPath_1.lineTo(0 + mThornPadding_1, y);
            mHexagonPath_1.close();
            canvas.save();
            for (int i = 0; i < 6; i++) {
                canvas.drawPath(mHexagonPath_1, mPaint);
                canvas.rotate(60, 0, 0);
            }
            canvas.restore();
        }
    

    5.绘制主干和角刺的的策略和边刺一样,只是角刺的起始位子位于垂直位置偏移30°,这个不打紧,直接想象当做垂直处理,绘制完后旋转30°,然后同上循环6次绘制其余5条,其中绘制角刺的方式(主干和边刺逻辑相似,不码了):

        public void drawCornerThorn(Canvas canvas, int h) {
            mPaint.setColor(Color.WHITE);
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setStrokeWidth(2);
            int y = -(int) (Math.sqrt(3) * mLength / 2);
            mHexagonPath_2.moveTo(0 - mCornerThornPadding_1, y);
            mHexagonPath_2.lineTo(0 - mCornerThornPadding_1 - mCornerThornPadding_2, y - mCornerThornHeight_1);
            mHexagonPath_2.lineTo(0, y - mCornerThornHeight_2);
            mHexagonPath_2.lineTo(0 + mCornerThornPadding_1 + mCornerThornPadding_2, y - mCornerThornHeight_1);
            mHexagonPath_2.moveTo(0 + mCornerThornPadding_1, y);
            mHexagonPath_2.close();
            canvas.save();
            canvas.translate(0, -h);
            canvas.rotate(-30, 0, y);
            canvas.drawPath(mHexagonPath_2, mPaint);
            canvas.rotate(60, 0, y);
            canvas.drawPath(mHexagonPath_2, mPaint);
            canvas.restore();
        }
    

    6.雪花的旋转采用值动画处理,动画过程改变view的旋转角度,每次重绘的时候提取到最新的旋转角度:

        /**
         * 雪花的旋转动画(属性)
         *
         * @param duration
         */
        public void snowRotateAnim(int duration) {
            if (null == mValueAnimator) {
                return;
            }
            mValueAnimator.setDuration(duration);
            mValueAnimator.setInterpolator(mLinearInterpolator);
            mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
            mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mAngle = (int) mValueAnimator.getAnimatedValue();
                }
            });
            mValueAnimator.start();
        }
    

    7.雪花向下移动:当超过边界,则重置该view的坐标位置:

        /**
         * 更新雪花的X坐标
         *
         * @param x
         */
        public void setOriginX(int x) {
            this.mOriginX += x;
            if (mOriginX > mW || mOriginX < -mWidth) {
                mOriginX = Utils.randomIntPositive(mW);
            }
        }
        /**
         * 更新雪花的Y坐标
         *
         * @param y
         */
        public void setOriginY(int y) {
            this.mOriginY += y;
            if (mOriginY > mH) {
                mOriginY = -mHeight;
            }
        }
    

    8.遗留问题,下雪动画一次性初始化了30个雪花对象,同时在onDraw中进行绘制,略有卡顿,优化策略待定。
    四、源码地址:
    自定义View-雪花和下雪动画

    相关文章

      网友评论

        本文标题:自定义View-雪花和下雪动画

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