欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android项目刮刮奖详解(一)

程序员文章站 2022-03-18 15:39:04
前言 最近正在学鸿洋大大的刮刮奖,感觉学有所得,便是来写篇详解(尽管网上有很多了,不过毕竟是自己写的,自己以后方便复习),正文开始 目标 实现画板功能 思路 我们需要自定义View来实现画板功能,之后再将其稍微改造即可。 关于自定义View,如果没有了解的同学建议先去了解一下,百度自定义View就会 ......

前言

最近正在学鸿洋大大的刮刮奖,感觉学有所得,便是来写篇详解(尽管网上有很多了,不过毕竟是自己写的,自己以后方便复习),正文开始

目标

实现画板功能

思路

我们需要自定义view来实现画板功能,之后再将其稍微改造即可。
关于自定义view,如果没有了解的同学建议先去了解一下,百度自定义view就会有许多相关教程了,
我在这里也就简单的提一下,自定义view常用的三大类,paint(画笔),path(路径),
canvas(画布),

  1. 继承view,实现构造方法

    四个构造方法,我们主要实现两个参数的构造方法即可

     private paint moutterpaint = new paint(); // 绘制线条的paint,即用户手指绘制path
     private path mpath = new path();//记录用户绘制的path
     private canvas mcanvas;//画布,可以画东西
     private bitmap mbitmap;//画布在此图片上画画
     private int mlastx;//x坐标
     private int mlasty;//y坐标
     private bitmap background;//这个是背景图,我们先不理
     public guaguaka(context context) {
         super(context);
     }
    
     public guaguaka(context context, @nullable attributeset attrs) {
         super(context, attrs);
         mpath = new path();
    
     }
    
     public guaguaka(context context, @nullable attributeset attrs, int defstyleattr) {
         super(context, attrs, defstyleattr);
     }
    
     public guaguaka(context context, @nullable attributeset attrs, int defstyleattr, int defstyleres) {
         super(context, attrs, defstyleattr, defstyleres);
     }
  2. 复写onmeasure方法

    我们首先获得view的宽高,然后以此的宽高创建一个画布,同时,对画笔进行一些设置

     @override
     protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
         super.onmeasure(widthmeasurespec, heightmeasurespec);
         log.d(tag, "onmeasure: 测量");
         int width = getmeasuredwidth();
         int height = getmeasuredheight();
         // 初始化bitmap
         mbitmap = bitmap.createbitmap(width, height, bitmap.config.argb_8888);//以获得的宽高创建一个32位的bitmap
         mcanvas = new canvas(mbitmap);//以bitmap创建了一个画布
         mcanvas.drawcolor(color.green);//设置画布的颜色为绿色
         //背景图,下一节解析此部分代码,先注释掉
         /*bitmapdrawable bitmap = (bitmapdrawable) getresources().getdrawable(r.drawable.rewrite6);
         background = bitmap.getbitmap();
         background = bitmap.createscaledbitmap(background,width,height,true);*/
         // 设置画笔
         moutterpaint.setcolor(color.blue);
         moutterpaint.setantialias(true);//使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢
         moutterpaint.setdither(true);//图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
         moutterpaint.setstyle(paint.style.stroke);
         moutterpaint.setstrokejoin(paint.join.round);//圆角,平滑
         moutterpaint.setstrokecap(paint.cap.round); //圆角
         moutterpaint.setstrokewidth(20); // 设置画笔宽度
     }   
  3. 复写ontouchevent方法

    我们在这里复写,处理一下用户的触摸事件当手指按到屏幕上的时候,path路径之中就使用moveto方法,移动到手指当前位置,
    invalidate刷新view,回调ondraw方法,(还没有画出来)。之后,手指移动,action处于是处于action_move的状态,path路径使用lineto方法(画直线),同时,将x,y坐标进行了更新,invalidate刷新view,回调ondraw方法,canvas通过drawpath使用画笔将path画了出来,之后如果用户没有抬起手指,则继续循环action_move中的步骤

     @override
     public boolean ontouchevent(motionevent event) {
         //当手指按到屏幕上的时候,path路径之中就使用moveto方法,移动到手指当前位置,invalidate刷新view,回调ondraw方法,(还没有画出来),canvas就将画笔移动到那个坐标
         //之后,手指移动,action是处于action_move的状态,path路径使用lineto方法(画直线),
         // 同时,将x,y坐标进行了更新,invalidate刷新view,回调ondraw方法,canvas通过drawpath使用画笔将path画了条出来(画直线),之后如果用户没有抬起手指,则继续循环action_move中的步骤
    
         int action = event.getaction();
         int x = (int) event.getx();//获得x坐标
         int y = (int) event.gety();//获得y坐标
         switch (action){
             case motionevent.action_down:
                 mlastx = x; 
                 mlasty = y; 
                 mpath.moveto(mlastx, mlasty);//之后回调ondraw方法canvas将path
                 break;
             case motionevent.action_move:
                 mpath.lineto(x, y);//之后回调ondraw方法时canvas画直线到(x,y)该点
                 mlastx = x;//更新x坐标
                 mlasty = y;//更新y坐标
                 break;
             default:break;
         }
         invalidate();//刷新view,回调ondraw方法
         log.d(tag, "ontouchevent: invalidate");
         return true;
    }
  4. 复写ondraw方法

    之后我们复写ondraw方法,在这里canvas用画笔开始画画

     @override
     protected void ondraw(canvas canvas) {
         log.d(tag, "ondraw: 画");
         //canvas.drawbitmap(background,0,0,null);//下一节解析,这里先注释掉
         //moutterpaint.setxfermode(new porterduffxfermode(porterduff.mode.dst_out));//下一节解析,注释掉
         mcanvas.drawpath(mpath, moutterpaint);//mcanvas是我们定义的画布,用户的每次的手指轨迹都被path记录下来,之后mcanvas就使用画笔将用户的手指轨迹画了出来
         canvas.drawbitmap(mbitmap, 0,0, null);//将mbitmap画出来
     }

ps:这里测试的时候发现mcanvas与canvas的顺序可以换个位置,影响不大
Android项目刮刮奖详解(一)

简单的流程图

Android项目刮刮奖详解(一)

补充 双缓冲技术

事实上,刮刮卡这个项目用到了双缓冲技术

双缓冲即在内存中创建一个与屏幕绘图区域一致的对象,先将图形绘制到内存中的这个对象上,再一次性将这个对象上的图形拷贝到屏幕上,这样能大大加快绘图的速度。

我们定义了一个mbitmap,之后使用这个mbitmap建立了一个画布,实际上我们的mcanvas只在mbitmap上画画

    mbitmap = bitmap.createbitmap(width, height, bitmap.config.argb_8888);//以获得的宽高创建一个32位的bitmap
    mcanvas = new canvas(mbitmap);//以bitmap创建了一个画布
    mcanvas.drawcolor(color.green);
    

mcanvas负责将用户的手指痕迹通过drawpath方法画出来

    mcanvas.drawpath(mpath, moutterpaint);

之后,ondraw方法里面的canvas则将mbitmap复制并显示出来

    canvas.drawbitmap(mbitmap, 0,0, null);//将mbitmap画出来(将mbitmap直接复制到view上显示)