[自定义SurfaceView] 气泡效果

这次的自定义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;
    }
}

在layout布局中放入这个view就可以了。 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值