Android 烟花效果实现

原创
2022/10/29 20:52
阅读数 367

效果图

  

二、代码实现

public class FireworksView extends View implements Runnable {

    private static final long V_SYNC_TIME = 50;
    private final DisplayMetrics mDM;
    private TextPaint mArcPaint;
    private List<FireDot> fireDots = new ArrayList<>();
    private List<Class<?  extends Drawer>> registry = new ArrayList<>();
    private int maxDashSize = 200;
    private long displayTime = 1_000L;
    private long currentDisplayTime = -1;
    private boolean isNextDrawingTimeScheduled = false;
    private boolean isStartUpdate = false;
    private Random radiusRnd = null;
    private TextPaint mDrawerPaint  = null;

    private static final int TYPE_EXPLORE = 0;
    private static final int TYPE_EXPAND = 1;
    private static final int TYPE_EXPAND_OUTLINE = 2;

    private int type = TYPE_EXPAND_OUTLINE;
    private int maxRadius;
    private int inlineRadius;

    public FireworksView(Context context) {
        this(context, null);
    }

    public FireworksView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FireworksView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mDM = getResources().getDisplayMetrics();
        initPaint();
        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                addRegistry(CircleDrawer.class);
                startPlay();
            }
        });
    }

    public static class CircleDrawer implements Drawer{

        int color = Color.BLACK;
        public CircleDrawer(){
            color = argb((float) Math.random(),(float)Math.random(),(float)Math.random());
        }
        @Override
        public void draw(Canvas canvas, Paint paint, FireDot dot) {
            int origin = paint.getColor();
            paint.setColor(color);
            canvas.drawCircle(dot.x,dot.y,3,paint);
            paint.setColor(origin);
        }

        public  int argb( float red, float green, float blue) {
            return ((int) (1 * 255.0f + 0.5f) << 24) |
                    ((int) (red   * 255.0f + 0.5f) << 16) |
                    ((int) (green * 255.0f + 0.5f) <<  8) |
                    (int) (blue  * 255.0f + 0.5f);
        }

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        if (widthMode != MeasureSpec.EXACTLY) {
            widthSize = mDM.widthPixels / 2;
        }

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (heightMode != MeasureSpec.EXACTLY) {
            heightSize = widthSize / 2;
        }
        radiusRnd = new Random(SystemClock.currentThreadTimeMillis());

        setMeasuredDimension(widthSize, heightSize);
    }

    private boolean isDebug() {
        return true;
    }

    public float dp2px(float dp) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mDM);
    }

    public float sp2px(float dp) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, dp, mDM);
    }

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

        int width = getWidth();
        int height = getHeight();
        if (width == 0 || height == 0) {
            return;
        }
        maxRadius = Math.min(width / 2, height / 2);
        inlineRadius = Math.min(width / 2, height / 2) / 5;
        int saveCount = canvas.save();
        canvas.translate(width / 2, height / 2);

        //canvas.drawCircle(0, 0, inlineRadius, mArcPaint);

        long t = getNextDrawingTime();
        if (t != -1) {
            for (FireDot dot : fireDots) {
                if(isStartUpdate){
                    double degree = Math.random() * 360;
                    if( degree> 360 ){
                        degree = 360;
                    }
                    double radians = Math.toRadians(degree);
                    int radius = radiusRnd.nextInt(inlineRadius/2) + 1;

                    float x = (float) (Math.cos(radians) * radius);
                    float y = (float) (Math.sin(radians) * radius);
                    dot.init(x,y,displayTime,radius,radians);
                }
                dot.t = t;
                onDrawEffect(dot,canvas,mDrawerPaint);
            }
            isStartUpdate = false;
            if(!isNextDrawingTimeScheduled) {
                isNextDrawingTimeScheduled = true;
                postDelayed(this, V_SYNC_TIME);
            }
        }
        canvas.restoreToCount(saveCount);

    }

    protected  void onDrawEffect(FireDot dot,Canvas canvas,Paint paint){
        if(type==TYPE_EXPLORE){
            exploreDraw(dot,canvas,paint);
        }else if(type==TYPE_EXPAND){
            expandDraw(dot,canvas,paint);
        }else if(type==TYPE_EXPAND_OUTLINE){
            expandToOutline(dot,canvas,paint);
        }
    }


    @Override
    public void run() {
        isNextDrawingTimeScheduled = false;
        if (currentDisplayTime < displayTime) {
            currentDisplayTime = Math.min(displayTime,currentDisplayTime+V_SYNC_TIME);
        } else {
            currentDisplayTime = -1;
        }
        postInvalidate();
    }

    private long getNextDrawingTime() {
        return currentDisplayTime;
    }

    public <T extends Drawer> void addRegistry( Class<T> drawer) {
        if (!this.registry.contains(drawer)) {
            this.registry.add(drawer);
        }
    }

    public void startPlay() {
        fillFireDashes();
        isStartUpdate = true;
        currentDisplayTime = -1;
        removeCallbacks(this);
        run();
    }

    private void fillFireDashes() {
        for (Class< ? extends  Drawer> drawable : this.registry) {
            try {
                FireDot dash = new FireDot(drawable.newInstance());
                if (fireDots.size() >= maxDashSize) {
                    break;
                }
                fireDots.add(dash);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        Random random = new Random(SystemClock.currentThreadTimeMillis());
        while (fireDots.size() < maxDashSize) {
            int nextInt = random.nextInt(this.registry.size());
            try {
                Class<? extends Drawer> drawable = registry.get(nextInt);
                FireDot dash = new FireDot(drawable.newInstance());
                fireDots.add(dash);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void setMaxDashSize(int maxDashSize) {
        this.maxDashSize = maxDashSize;
    }

    private void initPaint() {
        // 实例化画笔并打开抗锯齿
        mArcPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mArcPaint.setAntiAlias(true);
        mArcPaint.setStyle(Paint.Style.STROKE);
        mArcPaint.setStrokeCap(Paint.Cap.ROUND);

        mDrawerPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mDrawerPaint.setAntiAlias(true);
        mDrawerPaint.setStyle(Paint.Style.FILL);
        mDrawerPaint.setStrokeCap(Paint.Cap.ROUND);

    }

    public void setDisplayTime(long displayTime) {
        this.displayTime = displayTime;
    }


    private void exploreDraw(FireDot dot,Canvas canvas, Paint paint) {
        double speed = dot.radius*10F / displayTime;
        dot.x = (float) ((dot.radius + (speed * dot.t)) * Math.cos(dot.radians));
        dot.y = (float) ((dot.radius + (speed * dot.t)) * Math.sin(dot.radians));
        dot.drawer.draw(canvas,paint,dot);
    }


    private void expandToOutline(FireDot dot,Canvas canvas, Paint paint) {
        float speed = maxRadius * 1F / displayTime;
        double R = dot.radius + (speed * dot.t);
        if(R <= 2*inlineRadius) {
            dot.x = (float) ((dot.radius + (speed * dot.t)) * Math.cos(dot.radians));
            dot.y = (float) ((dot.radius + (speed * dot.t)) * Math.sin(dot.radians));
        }
        dot.drawer.draw(canvas,paint,dot);
    }

    private void expandDraw(FireDot dot,Canvas canvas, Paint paint) {
        float C = (float) (inlineRadius/(inlineRadius - dot.radius));
        if(C>4){
            C = 4;
        }
        float speed = (float) ((maxRadius * 1F / dot.duration)  +(C* (inlineRadius  /dot.duration)));

        dot.x = (float) ((dot.radius + (speed * dot.t))*Math.cos(dot.radians));
        dot.y = (float) ((dot.radius + (speed * dot.t))*Math.sin(dot.radians));

        dot.drawer.draw(canvas,paint,dot);
    }

    private static class FireDot {
        private final Drawer drawer;
        private float x;
        private float y;
        private long duration;
        private float startX;
        private float startY;
        private double radius;
        private double radians;
        private  long t;

        public FireDot(Drawer drawer) {
            this.drawer = drawer;
        }

        public void init(float x, float y, long duration,float radius, double radians) {
            this.x = x;
            this.y = y;
            this.startX = x;
            this.startY = y;
            this.duration = duration;
            this.radius = radius;
            this.radians = radians;
        }
    }

    public interface Drawer {
           void draw(Canvas canvas,Paint paint,FireDot dot);
    }
}

 

 

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部