[自定义SurfaceView] 气泡效果

气泡效果

image

这次的自定义view的要求效果为:能随机生成气泡 气泡会匀速上浮 保持屏幕始终存在n个气泡;

(一)随机生成气泡

首先要绘制一个气泡需要以下几个参数:
float x, y; 气泡坐标
int radius 气泡半径
int color 气泡颜色
int speed 气泡移动速度
为了方便绘制这里建议把这几个参数分装起来成为一个气泡对象。

//定义buble 对象
public class Bubble{
//颜色
public int color;
//位置
public float point_y;
public float point_x;
//移动速度
public float speed;
//半径
public int radius;
public Bubble(){}
}

现在要做到随机生成气泡的color,x轴位置 ,移动速度,半径。y轴位置固定为view的最底部。
这里写一个Bubble_create(int width)方法 传入当前view的宽度。

 private   Bubble Bubble_create(int witdh){
        Bubble bubble = new Bubble();
        Random rand = new Random();
        switch (rand.nextInt(10)){
            case 0:
                bubble.color = Color.BLUE;
                break;
            case 1:
                bubble.color = Color.BLACK;
                break;
            case 2:
                bubble.color = Color.CYAN;
                break;
            case 3:
                bubble.color = Color.DKGRAY;
                break;
            case 4:
                bubble.color = Color.GRAY;
                break;
            case 5:
                bubble.color = Color.GREEN;
                break;
            case 6:
                bubble.color = Color.YELLOW;
                break;
            case 7:
                bubble.color = Color.LTGRAY;
                break;
            case 8:
                bubble.color = Color.MAGENTA;
                break;
            case 9:
                bubble.color = Color.RED;
                break;

            default:
                bubble.color = Color.BLUE;
                break;
        }
        bubble.radius = rand.nextInt(70)+10;
        bubble.point_x = rand.nextInt(witdh);
        bubble.point_y = getHeight();
        bubble.speed = rand.nextInt(10)+1;
        return bubble;
    }
//调用方法
Bubble mbuble = Bubble_create(getWidth());

(二)气泡匀速上升

重点!重点!这里开始自定义surfaceView.
先搭自定义surfaceView的框架
第一步: 继承suerfaceview 实现它的几个构造函数。
第二步: implements SurfaceHolder.Callback与 Runnable的接口

//surfaceview 框架
public class BubbleView extends SurfaceView implements SurfaceHolder.Callback,Runnable {
    //surfaceHolders 这个很重要用来锁定canvas和解锁canvas
    private SurfaceHolder mSurfaceHolder;
    //程序运行标志 用来控制是否继续绘制view
    private  boolean running;
    // 画布
    private Canvas mCanvas;


    public BubbleView(Context context) {
        super(context);
        init();
    }

    public BubbleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public BubbleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
  //将初始化操作放到这里
    protected void init(){
        mSurfaceHolder =  getHolder();
        mSurfaceHolder.addCallback(this);
        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setKeepScreenOn(true);
    }

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

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

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

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        running = true;
        new Thread(this).start();
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
//        running = false;
    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        running = false;
    }

    @Override
    public void run() {
        //运行线程 循环绘制
        while(running){
            draw();
        }
        try {
            //等60毫秒绘制一次
            Thread.sleep(60);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
  //这里执行绘制方法
    public void draw(){
        try {
        mCanvas = mSurfaceHolder.lockCanvas();
      //这里很重要 每次绘制的时候绘制一个白色背景来作为刷新界面的方式
      //因为surfaceview 不会清除上次绘制的图形
        mCanvas.drawColor(Color.WHITE);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (mCanvas != null){
                mSurfaceHolder.unlockCanvasAndPost(mCanvas);
            }
        }
    }
}

第三步:实现气泡上升

//定义
 private List<Bubble> bubbles;
 private Paint bubbles_paint;
//初始化
 bubbles = new ArrayList<>();
 bubbles_paint = new Paint();
 bubbles_paint.setStyle(Paint.Style.FILL);
//下面一部分要放到绘制里面
//这里是遍历气泡list里的所有气泡并且绘制出来
 for (Bubble temp_bubble:bubbles) {
  //这里一段是实现气泡的颜色渐变
  RadialGradient radialGradient =new RadialGradient(temp_bubble.point_x,temp_bubble.point_y,temp_bubble.radius, new int[]{Color.WHITE, 0xFFf1f2f2, temp_bubble.color },null, Shader.TileMode.CLAMP);
  bubbles_paint.setShader(radialGradient);
//这里绘制气泡圆形
  mCanvas.drawCircle(temp_bubble.point_x,temp_bubble.point_y,temp_bubble.radius,bubbles_paint);
//绘制完后把气泡的y轴坐标往上挪speed的距离
  temp_bubble.point_y -= temp_bubble.speed;
        }

(三)保持屏幕始终存在n个气泡:

1.在每次绘制的时候判断气泡list的数量是否少于n个少于n个的话就创建。
2.当气泡飞出屏幕外的时候要把它从列表中移除掉。

  //1.在每次绘制的时候判断气泡list的数量是否少于n个少于n个的话就创建。
   while(bubbles.size()<=10){
            Log.d(this.toString(),bubbles.size()+"");
            bubbles.add(Bubble_create(getWidth()));
        }
     
      ····
      这里绘制气泡 
      ····
   // 2.当气泡飞出屏幕外的时候要把它从列表中移除掉。
  //这里是创建一个temp气泡列表 把还在屏幕里的气泡塞到这个列表中,最后替换掉之前的气泡列表。
   List<Bubble> temp_bubbles = new ArrayList<>();
    for(Bubble temp_bubble:bubbles){
            if((int)temp_bubble.point_y+temp_bubble.radius>=0){
                temp_bubbles.add(temp_bubble);
            }
     }
     bubbles = temp_bubbles;

所有需求都实现后把它们整合到自定义view里面 最后的源码:

public class BubbleView extends SurfaceView implements SurfaceHolder.Callback,Runnable {


    private SurfaceHolder mSurfaceHolder;
    private  boolean running;
    // 画布
    private Canvas mCanvas;

    //气泡列队
    private List<Bubble> bubbles;
    private Paint bubbles_paint;


    public BubbleView(Context context) {
        super(context);
        init();
    }

    public BubbleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public BubbleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    protected void init(){
        mSurfaceHolder =  getHolder();
        mSurfaceHolder.addCallback(this);
        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setKeepScreenOn(true);
        bubbles = new ArrayList<>();
        bubbles_paint = new Paint();
        bubbles_paint.setStyle(Paint.Style.FILL);

    }

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

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

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

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        running = true;
        new Thread(this).start();
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
//        running = false;
    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        running = false;
    }

    @Override
    public void run() {
        while(running){
            draw();

        }
        try {
            Thread.sleep(60);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void draw(){
        try {
        mCanvas = mSurfaceHolder.lockCanvas();
        mCanvas.drawColor(Color.WHITE);
        while(bubbles.size()<=10){
            Log.d(this.toString(),bubbles.size()+"");
            bubbles.add(Bubble_create(getWidth()));
        }
        for (Bubble temp_bubble:bubbles) {
            RadialGradient radialGradient =new RadialGradient(temp_bubble.point_x,temp_bubble.point_y,temp_bubble.radius, new int[]{Color.WHITE, 0xFFf1f2f2, temp_bubble.color },null, Shader.TileMode.CLAMP);
            bubbles_paint.setShader(radialGradient);
            mCanvas.drawCircle(temp_bubble.point_x,temp_bubble.point_y,temp_bubble.radius,bubbles_paint);
            temp_bubble.point_y -= temp_bubble.speed;
        }
        List<Bubble> temp_bubbles = new ArrayList<>();
        for(Bubble temp_bubble:bubbles){
            if((int)temp_bubble.point_y+temp_bubble.radius>=0){
                temp_bubbles.add(temp_bubble);
            }
        }
        bubbles = temp_bubbles;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (mCanvas != null){
                mSurfaceHolder.unlockCanvasAndPost(mCanvas);
            }
        }


    }


    //定义buble 对象
    public class Bubble{
        //颜色
        public int color;
        //位置
        public float point_y;
        public float point_x;
        //移动速度
        public float speed;
        //半径
        public int radius;

        public Bubble(){

        }


    }

    private   Bubble Bubble_create(int witdh){
        Bubble bubble = new Bubble();
        Random rand = new Random();
        switch (rand.nextInt(10)){
            case 0:
                bubble.color = Color.BLUE;
                break;
            case 1:
                bubble.color = Color.BLACK;
                break;
            case 2:
                bubble.color = Color.CYAN;
                break;
            case 3:
                bubble.color = Color.DKGRAY;
                break;
            case 4:
                bubble.color = Color.GRAY;
                break;
            case 5:
                bubble.color = Color.GREEN;
                break;
            case 6:
                bubble.color = Color.YELLOW;
                break;
            case 7:
                bubble.color = Color.LTGRAY;
                break;
            case 8:
                bubble.color = Color.MAGENTA;
                break;
            case 9:
                bubble.color = Color.RED;
                break;

            default:
                bubble.color = Color.BLUE;
                break;
        }
        bubble.radius = rand.nextInt(70)+10;
        bubble.point_x = rand.nextInt(witdh);
        bubble.point_y = getHeight();
        bubble.speed = rand.nextInt(10)+1;

        return bubble;
    }
}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容