Android开发中秋之嫦娥奔月

814 阅读3分钟

我正在参加中秋创意投稿大赛,详情请看:中秋创意投稿大赛

完成效果:

前言

大家公司的中秋福利都发了吗?今年我们公司发了一盒月饼和一箱小零食,去年发了一盒月饼和一箱杂粮。虽然出来工作后几乎都是身在他乡过得中秋节,不能和家人团圆,但是还是要祝福大家中秋快乐的。作为一名Android开发者程序员实在没有什么好的创意,奔着尽可能看上去真实的动画效果和符合中秋主题,在此融入了月亮、星空、流行、云朵、团圆、嫦娥、月饼等元素,并且附有百度百科借鉴来的中秋小知识哦~

百度百科地址:中秋节

主要效果

1、嫦娥奔月

2、闪动的星空

3、飘动的云朵

主要运用技术

1、组合动画

2、自定义View

属性动画ObjectAnimator介绍

• translationX和translationY:用来沿着X轴或者Y轴进行平移。

 • rotation、rotationX、rotationY:用来围绕View的支点进行旋转。

 • scaleX、scaleY:横向拉伸和纵向拉伸 

 • alpha:透明度,默认是1(不透明),0代表完全透明。

 • x和y:描述View对象在其容器中的最终位置。

组合动画AnimatorSet介绍

• after(Animator anim):将现有动画插入到传入的动画之后执行。

 • after(long delay):将现有动画延迟指定毫秒后执行。

 • before(Animator anim):将现有动画插入到传入的动画之前执行。

 • with(Animator anim):将现有动画和传入的动画同时执行。 

嫦娥奔月实现

嫦娥奔月其实非常简单就是一张图片用上组合动画,把图片进行平移、缩放、和渐变

//平移
ObjectAnimator animator1 = ObjectAnimator.ofFloat(binding.ivChange, "translationX", 1000f, 0f).setDuration(1000 * 10);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(binding.ivChange, "translationY", 1500f, 0f).setDuration(1000 * 10);
//透明度渐变
ObjectAnimator animator3 = ObjectAnimator.ofFloat(binding.ivChange, "alpha", 1f, 0f).setDuration(1000 * 1);
//缩放
ObjectAnimator animator4 = ObjectAnimator.ofFloat(binding.ivChange, "scaleX", 1.5f, 0.5f).setDuration(1000 * 10);
ObjectAnimator animator5 = ObjectAnimator.ofFloat(binding.ivChange, "scaleY", 1.5f, 0.5f).setDuration(1000 * 10);
//组合动画
AnimatorSet set = new AnimatorSet();
set.play(animator1).with(animator2).with(animator4).with(animator5).before(animator3);
//开始动画
set.start();

星空及流行的实现

初始化背景和星空画笔

private void init() {
        starBitmap = zoomImg(BitmapFactory.decodeResource(getResources(), R.drawable.snow), 20, 20);
        //初始化 画笔
        weatherPaint = new Paint();
        weatherPaint.setAntiAlias(true);
        weatherPaint.setStyle(Paint.Style.FILL);

        starPaint = new Paint();
        starPaint.setMaskFilter(new BlurMaskFilter(1, BlurMaskFilter.Blur.NORMAL));
        starPaint.setColor(Color.WHITE);
        starPaint.setStyle(Paint.Style.FILL);

        initAlphaFilter();
  }

public Bitmap zoomImg(Bitmap bm, int newWidth, int newHeight) {
        // 获得图片的宽高
        int width = bm.getWidth();
        int height = bm.getHeight();
        // 计算缩放比例
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // 取得想要缩放的matrix参数
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
        // 得到新的图片
        Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
        return newbm;
    }

 private void initAlphaFilter() {
        for (int i = 0; i < 100; i++) {
            alphaFilters[i] = new ColorMatrixColorFilter(new float[]{
                    1, 0, 0, 0, 0,
                    0, 1, 0, 0, 0,
                    0, 0, 1, 0, 0,
                    0, 0, 0, 0.01f * i, 0});
        }
  }

初始化流行星星参数:

private void initStarMeteorParams() {
        meteorParams.clear();
        starParams.clear();

        if (width == 0 || height == 0) {
            return;
        }

        float widthRatio = Unit.px2dip(context, width) / 392.0f;
        for (int i = 0; i < 50; i++) {
            int index = (int) (Math.random() * 2);
            StarParam starParam = new StarParam(index);
            starParam.init(width, height, widthRatio);
            starParams.add(starParam);
        }

        for (int i = 0; i < 2; i++) {
            MeteorParam param = new MeteorParam();
            param.init(width, height, widthRatio);
            meteorParams.add(param);
        }
    }

绘制背景、星星和流行

   /**
     * 绘制背景
     */
    private void drawWeatherBg(Canvas canvas) {
        int[] color = new int[]{Color.parseColor(context.getResources().getStringArray(R.array.weather_cloudy_light)[0]),
                Color.parseColor(context.getResources().getStringArray(R.array.weather_cloudy_light)[1])};
        mBackgroundShader = new LinearGradient(0, 0, 0, height, color[0], color[1], Shader.TileMode.MIRROR);
        weatherPaint.setShader(mBackgroundShader);
        weatherPaint.setShadowLayer(15, 10, 10, Color.GRAY);
        backgroundRect = new Rect(0, 0, width, height);
        canvas.drawRect(backgroundRect, weatherPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

    /**
     * 绘制星星 和流星
     */
    private void drawStarMeteor(Canvas canvas) {
        if (starParams.size() > 0) {
            for (StarParam param : starParams) {
                drawStar(param, canvas);
            }
        }
        if (meteorParams.size() > 0) {
            for (MeteorParam param : meteorParams) {
                drawMeteor(param, canvas);
            }
        }
    }

    /**
     * 绘制星星
     *
     * @param star
     * @param canvas
     */
    private void drawStar(StarParam star, Canvas canvas) {
        if (star == null) {
            return;
        }
        canvas.save();
        int index = (int) (star.alpha * 100);

        if (index < 0) {
            index = 0;
        }
        if (index > 99) {
            index = 99;
        }
        starIdentity = alphaFilters[index];
        starPaint.setColorFilter(starIdentity);
        canvas.scale((float) star.scale, (float) star.scale);
        canvas.drawBitmap(starBitmap, (float) star.x, (float) star.y, starPaint);
        canvas.restore();
        star.move();

    }

    /**
     * 绘制流星
     */
    private void drawMeteor(MeteorParam meteor, Canvas canvas) {
        if (meteor == null) {
            return;
        }

        canvas.save();
        if (mStarShader == null) {
            mStarShader = new LinearGradient(0, 0, 0, width, Color.parseColor("#FFFFFFFF"), Color.parseColor("#00FFFFFF"), Shader.TileMode.MIRROR);
        }

        starPaint.setShader(mStarShader);
        starPaint.setColorFilter(null);
        starPaint.setAntiAlias(true);
        canvas.rotate((float) (Math.PI * meteor.radians));
        float scale = Unit.px2dip(context, width) / 392.0f;
        canvas.scale(scale, scale);
        canvas.translate(
                (float) meteor.translateX, (float) (Math.tan(Math.PI * 0.1) * Unit.dip2px(context, meteorWidth) + meteor.translateY));
        if (starRectF == null) {
            starRectF = new RectF(0, 0, Unit.dip2px(context, meteorWidth), Unit.dip2px(context, meteorHeight));
        }
        float starRadius = Unit.dip2px(context, radius);
        canvas.drawRoundRect(starRectF, starRadius, starRadius, starPaint);
        meteor.move(context);
        canvas.restore();
    }

星空和流行绘制参考:包含雨,雪,雷电,雾等多种天气效果。

dp、px互转工具

public class Unit {
    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}

循环漂浮的云的实现

private Runnable task = new Runnable() {
        public void run() {
            handler.postDelayed(this, 30 * 1000);//设置循环时间,此处是5秒
            //平移
            ObjectAnimator.ofFloat(binding.ivCloud, "translationX", -1000f, 1200f).setDuration(1000 * 30).start();
        }
    };

调用:

//保持屏幕常亮
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

//立即调用
handler.post(task);

文字对齐使用:AlignTextView

完整代码请查看:流行效果和嫦娥奔月动画。

Android安装包体验:去下载