Android:Canvas

来源:互联网 发布:淘宝人工云客服没有了 编辑:程序博客网 时间:2024/05/02 04:36
当我们调整好画笔之后,现在需要绘制到画布上,这就得用Canvas类了。在Android中既然把Canvas当做画布,那么就可以在画布上绘制我们想要的任何东西。除了在画布上绘制之外,还需要设置一些关于画布的属性,比如,画布的颜色、尺寸等。下面来分析Android中Canvas有哪些功能,Canvas提供了如下一些方法:
    Canvas(): 创建一个空的画布,可以使用setBitmap()方法来设置绘制具体的画布。
    Canvas(Bitmap bitmap): 以bitmap对象创建一个画布,则将内容都绘制在bitmap上,因此bitmap不得为null。
    Canvas(GL gl): 在绘制3D效果时使用,与OpenGL相关。
    drawColor: 设置Canvas的背景颜色。
    setBitmap:  设置具体画布。
    clipRect: 设置显示区域,即设置裁剪区。
    isOpaque:检测是否支持透明。
    rotate:  旋转画布
    setViewport:  设置画布中显示窗口。
    skew:  设置偏移量。

   
    上面列举了几个常用的方法。在游戏开发中,我们可能需要对某个精灵执行旋转、缩放和一些其它操作。我们可以通过旋转画布来实现,但是旋转画布时会旋转画布上的所有对象,而我们只是需要旋转其中的一个,这时就需要用到save 方法来锁定需要操作的对象,在操作之后通过 restore 方法来解除锁定,下面我们先来看一下运行效果吧。



  我们对左边的矩形执行了旋转操作,而没有旋转右边的矩形,由于我们设置了裁剪区域,因此左边的矩形只能看到一部分,下面让我们来看看代码 这里我只贴出了我们自己的 View类
GameView Activity类不贴出了 就在里边 new 一个GameView类 然后设置布局 然后main.xml也不贴出来了 因为它根本就没用到。
   GameView类
Java代码  收藏代码
  1. package com.yarin.android.Examples_05_04;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Canvas;  
  5. import android.graphics.Color;  
  6. import android.graphics.Paint;  
  7. import android.graphics.Rect;  
  8. import android.view.KeyEvent;  
  9. import android.view.MotionEvent;  
  10. import android.view.View;  
  11.   
  12. public class GameView extends View implements Runnable {  
  13.     /* 声明Paint对象 */  
  14.     private Paint mPaint = null;  
  15.   
  16.     public GameView(Context context) {  
  17.         super(context);  
  18.         /* 构建对象 */  
  19.         mPaint = new Paint();  
  20.   
  21.         /* 开启线程 */  
  22.         new Thread(this).start();  
  23.     }  
  24.   
  25.     public void onDraw(Canvas canvas) {  
  26.         super.onDraw(canvas);  
  27.   
  28.         /* 设置画布的颜色 */  
  29.         canvas.drawColor(Color.BLACK);  
  30.   
  31.         /* 设置取消锯齿效果 */  
  32.         mPaint.setAntiAlias(true);  
  33.   
  34.         /* 设置裁剪区域 */  
  35.         canvas.clipRect(1010280260);  
  36.   
  37.         /* 线锁定画布 */  
  38.         canvas.save();  
  39.         /* 旋转画布 */  
  40.         canvas.rotate(45.0f);  
  41.   
  42.         /* 设置颜色及绘制矩形 */  
  43.         mPaint.setColor(Color.RED);  
  44.         canvas.drawRect(new Rect(151514070), mPaint);  
  45.   
  46.         /* 解除画布的锁定 */  
  47.         canvas.restore();  
  48.   
  49.         /* 设置颜色及绘制另一个矩形 */  
  50.         mPaint.setColor(Color.GREEN);  
  51.         canvas.drawRect(new Rect(15075260120), mPaint);  
  52.     }  
  53.   
  54.     // 触笔事件  
  55.     public boolean onTouchEvent(MotionEvent event) {  
  56.         return true;  
  57.     }  
  58.   
  59.     // 按键按下事件  
  60.     public boolean onKeyDown(int keyCode, KeyEvent event) {  
  61.         return true;  
  62.     }  
  63.   
  64.     // 按键弹起事件  
  65.     public boolean onKeyUp(int keyCode, KeyEvent event) {  
  66.         return false;  
  67.     }  
  68.   
  69.     public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {  
  70.         return true;  
  71.     }  
  72.   
  73.     public void run() {  
  74.         while (!Thread.currentThread().isInterrupted()) {  
  75.             try {  
  76.                 Thread.sleep(100);  
  77.             } catch (InterruptedException e) {  
  78.                 Thread.currentThread().interrupt();  
  79.             }  
  80.             // 使用postInvalidate可以直接在线程中更新界面  
  81.             postInvalidate();  
  82.         }  
  83.     }  

  84. ————————————————————————————————————————————————
  85. android Canvas举例
    在进行旋转、缩放时,可以通过旋转画布来实现。但旋转画布会旋转画布上所有对象,如果需要旋转其中一个对象,使用save方法来锁定需要操作的对象,在操作之后通过restore方法来解除锁定。例如下方实例中,对左边的矩形执行了旋转操作,而没有旋转右边的矩形。
    public class GameView extends View implements Runnable
    {
    /* 声明Paint对象 */
    private Paint mPaint = null;

    public GameView(Context context)
    {
    super(context);
    /* 构建对象 */
    mPaint = new Paint();

    /* 开启线程 */
    new Thread(this).start();
    }

    public void onDraw(Canvas canvas)
    {
    super.onDraw(canvas);

    /* 设置画布的颜色 */
    canvas.drawColor(Color.BLACK);

    /* 设置取消锯齿效果 */
    mPaint.setAntiAlias(true);

    /* 设置裁剪区域 */
    canvas.clipRect(10, 10, 280, 260);

    /* 线锁定画布 */
    canvas.save();
    /* 旋转画布 */
    canvas.rotate(45.0f);

    /* 设置颜色及绘制矩形 */
    mPaint.setColor(Color.RED);
    canvas.drawRect(new Rect(15,15,140,70), mPaint);

    /* 解除画布的锁定 */
    canvas.restore();

    /* 设置颜色及绘制另一个矩形 */
    mPaint.setColor(Color.GREEN);
    canvas.drawRect(new Rect(150,75,260,120), mPaint);
    }

    // 触笔事件
    public boolean onTouchEvent(MotionEvent event)
    {
    return true;
    }


    // 按键按下事件
    public boolean onKeyDown(int keyCode, KeyEvent event)
    {
    return true;
    }


    // 按键弹起事件
    public boolean onKeyUp(int keyCode, KeyEvent event)
    {
    return false;
    }


    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)
    {
    return true;
    }


    public void run()
    {
    while (!Thread.currentThread().isInterrupted())
    {
    try
    {
    Thread.sleep(100);
    }
    catch (InterruptedException e)
    {
    Thread.currentThread().interrupt();
    }
    // 使用postInvalidate可以直接在线程中更新界面
    postInvalidate();
    }
    }
    }

    —————————————————————————————————————————————————

    Android Canvas drawArc方法介绍

  86. public void drawArc(RectF oval, float startAngle, float sweepAngle,boolean useCenter, Paint paint)

    • oval :指定圆弧的外轮廓矩形区域。
    • startAngle: 圆弧起始角度,单位为度。
    • sweepAngle: 圆弧扫过的角度,顺时针方向,单位为度。
    • useCenter: 如果为True时,在绘制圆弧时将圆心包括在内,通常用来绘制扇形。
    • paint: 绘制圆弧的画板属性,如颜色,是否填充等。

    本例演示了drawArc的四种不同用法,

    1. 填充圆弧但不含圆心:






    mPaints[0]= new Paint();
    mPaints[0].setAntiAlias(true);
    mPaints[0].setStyle(Paint.Style.FILL);
    mPaints[0].setColor(0x88FF0000);
    mUseCenters[0]= false;

    2. 填充圆弧带圆心(扇形)


    mPaints[1]= new Paint(mPaints[0]);
    mPaints[1].setColor(0x8800FF00);
    mUseCenters[1]= true;

    3. 只绘圆周,不含圆心


    mPaints[2]= new Paint(mPaints[0]);
    mPaints[2].setStyle(Paint.Style.STROKE);
    mPaints[2].setStrokeWidth(4);
    mPaints[2].setColor(0x880000FF);
    mUseCenters[2]= false;

    4. 只绘圆周,带圆心(扇形)


    mPaints[3]= new Paint(mPaints[2]);
    mPaints[3].setColor(0x88888888);
    mUseCenters[3]= true;

    本例的onDraw


    protected void onDraw(Canvascanvas) {
     canvas.drawColor(Color.WHITE);
     
     drawArcs(canvas,mBigOval, mUseCenters[mBigIndex],
     mPaints[mBigIndex]);
     
     for (int i= 0; i< 4; i++){
     drawArcs(canvas,mOvals[i], mUseCenters[i], mPaints[i]);
     }
     
     mSweep +=SWEEP_INC;
     if (mSweep> 360){
     mSweep-= 360;
     mStart +=START_INC;
     if (mStart>= 360){
     mStart-= 360;
     }
     mBigIndex = (mBigIndex+ 1) %mOvals.length;
     }
     invalidate();
     }

    同样onDraw之中调用invalidate(),会再触发onDraw,从而不停刷新显示,startAngle,sweepAngle周而复始,形成动画效果,最上的大图顺序显示drawArc的这四种用法:

    Paint.Style.STROKE 表示当前只绘制图形的轮廓,而Paint.Style.FILL表示填充图形。

    Android <wbr>Canvas <wbr>drawArc方法介绍
  87. ——————————————————————————————————————————————
  88. Android中使用图形处理引擎,2D部分是android SDK内部自己提供,3D部分是用Open GL ES 1.0。今天我们主要要了解的是2D相关的,如果你想看3D的话那么可以跳过这篇文章。

    大部分2D使用的api都在android.graphics和android.graphics.drawable包中。他们提供了图形处理相关的: Canvas、ColorFilter、Point(点)和RetcF(矩形)等,还有一些动画相关的:AnimationDrawable、BitmapDrawable和TransitionDrawable等。以图形处理来说,我们最常用到的就是在一个View上画一些图片、形状或者自定义的文本内容,这里我们都是使用Canvas来实现的。你可以获取View中的Canvas对象,绘制一些自定义形状,然后调用View. invalidate方法让View重新刷新,然后绘制一个新的形状,这样达到2D动画效果。下面我们就主要来了解下Canvas的使用方法。

    Canvas对象的获取方式有两种:一种我们通过重写View.onDraw方法,View中的Canvas对象会被当做参数传递过来,我们操作这个Canvas,效果会直接反应在View中。另一种就是当你想创建一个Canvas对象时使用的方法:

    1
    2
    Bitmap b = Bitmap.createBitmap(100,100, Bitmap.Config.ARGB_8888);
    Canvas c =newCanvas(b);

    上面代码创建了一个尺寸是100*100的Bitmap,使用它作为Canvas操作的对象,这时候的Canvas就是使用创建的方式。当你使用创建的Canvas在bitmap上执行绘制方法后,你还可以将绘制的结果提交给另外一个Canvas,这样就可以达到两个Canvas协作完成的效果,简化逻辑。但是android SDK建议使用View.onDraw参数里提供的Canvas就好,没必要自己创建一个新的Canvas对象。接下来我们看看Canvas提供我们哪些绘制图形的方法。我们创建一个自定义View对象,使用onDraw方法提供的Canvas进行绘制图形。

    CanvasDemoActivity.java:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    packagecom.android777.demo.uicontroller.graphics;
     
    importandroid.app.Activity;
    importandroid.content.Context;
    importandroid.graphics.Canvas;
    importandroid.graphics.Color;
    importandroid.graphics.Paint;
    importandroid.os.Bundle;
    importandroid.view.View;
     
    publicclassCanvasDemoActivityextendsActivity {
     
        @Override
        protectedvoidonCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
     
            setContentView(newCustomView1(this));
     
        }
     
        /**
         * 使用内部类 自定义一个简单的View
         * @author Administrator
         *
         */
        classCustomView1extendsView{
     
            Paint paint;
     
            publicCustomView1(Context context) {
                super(context);
                paint =newPaint();//设置一个笔刷大小是3的黄色的画笔
                paint.setColor(Color.YELLOW);
                paint.setStrokeJoin(Paint.Join.ROUND);
                paint.setStrokeCap(Paint.Cap.ROUND);
                paint.setStrokeWidth(3);
            }
     
            //在这里我们将测试canvas提供的绘制图形方法
            @Override
            protectedvoidonDraw(Canvas canvas) {
     
            }
     
        }
     
    }

     

     

    执行结果是一片黑色的区域,因为在自定义的CustomView1中,我们没有做任何的绘制操作。canvas提供的绘制图形的方法都是以draw开头的,我们可以查看api:

    从上面方法的名字看来我们可以知道Canvas可以绘制的对象有:弧线(arcs)、填充颜色(argb和color)、Bitmap、圆(circle和oval)、点(point)、线(line)、矩形(Rect)、图片(Picture)、圆角矩形(RoundRect)、文本(text)、顶点(Vertices)、路径(path)。通过组合这些对象我们可以画出一些简单有趣的界面出来,但是光有这些功能还是不够的,如果我要画一个仪表盘(数字围绕显示在一个圆圈中)呢? 幸好Android还提供了一些对Canvas位置转换的方法:rorate、scale、translate、skew(扭曲)等,而且它允许你通过获得它的转换矩阵对象(getMatrix方法,不知道什么是转换矩阵?看这里)直接操作它。这些操作就像是虽然你的笔还是原来的地方画,但是画纸旋转或者移动了,所以你画的东西的方位就产生变化。为了方便一些转换操作,Canvas还提供了保存和回滚属性的方法(save和restore),比如你可以先保存目前画纸的位置(save),然后旋转90度,向下移动100像素后画一些图形,画完后调用restore方法返回到刚才保存的位置。下面我们就演示下canvas的一些简单用法:

    1
    2
    3
    4
    protectedvoidonDraw(Canvas canvas) {
     
        canvas.drawCircle(100,100,90, paint);
    }

    效果是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @Override
    protectedvoidonDraw(Canvas canvas) {
     
        //绘制弧线区域
     
        RectF rect =newRectF(0,0,100,100);
     
        canvas.drawArc(rect,//弧线所使用的矩形区域大小
                0//开始角度
                90,//扫过的角度
                false,//是否使用中心
                paint);
     
    }


    使用下面的代码:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    protectedvoidonDraw(Canvas canvas) {
     
        //绘制弧线区域
     
        RectF rect =newRectF(0,0,100,100);
     
        canvas.drawArc(rect,//弧线所使用的矩形区域大小
                0//开始角度
                90,//扫过的角度
                true,//是否使用中心
                paint);
     
    }

     

    两图对比我们可以发现,当drawArcs(rect,startAngel,sweepAngel,useCenter,paint)中的useCenter为false时,弧线区域是用弧线开始角度和结束角度直接连接起来的,当useCenter为true时,是弧线开始角度和结束角度都与中心点连接,形成一个扇形。

     

    1
    2
    3
    4
    5
    protectedvoidonDraw(Canvas canvas) {
     
        canvas.drawColor(Color.BLUE);
     
    }

     

    canvas.drawColor是直接将View显示区域用某个颜色填充满。

     

    1
    2
    3
    4
    5
    6
    7
    @Override
    protectedvoidonDraw(Canvas canvas) {
     
        //画一条线
        canvas.drawLine(10,10,100,100, paint);
     
    }

     

    Canvas.drawOval:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Override
    protectedvoidonDraw(Canvas canvas) {
     
        //定义一个矩形区域
        RectF oval =newRectF(0,0,200,300);
        //矩形区域内切椭圆
        canvas.drawOval(oval, paint);
     
    }

     

    canvas.drawPosText:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Override
    protectedvoidonDraw(Canvas canvas) {
     
        //按照既定点 绘制文本内容
        canvas.drawPosText("Android777",newfloat[]{
                10,10,//第一个字母在坐标10,10
                20,20,//第二个字母在坐标20,20
                30,30,//....
                40,40,
                50,50,
                60,60,
                70,70,
                80,80,
                90,90,
                100,100
        }, paint);
     
    }

     

    canvas.drawRect:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        @Override
        protectedvoidonDraw(Canvas canvas) {
     
            RectF rect =newRectF(50,50,200,200);
     
            canvas.drawRect(rect, paint);
     
        }
     
    }

     

    canvas.drawRoundRect:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Override
    protectedvoidonDraw(Canvas canvas) {
     
        RectF rect =newRectF(50,50,200,200);
     
        canvas.drawRoundRect(rect,
                            30,//x轴的半径
                            30,//y轴的半径
                            paint);
     
    }

     

    canvas.drawPath:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Override
    protectedvoidonDraw(Canvas canvas) {
     
        Path path =newPath();//定义一条路径
        path.moveTo(10,10);//移动到 坐标10,10
        path.lineTo(50,60);
        path.lineTo(200,80);
        path.lineTo(10,10);
     
        canvas.drawPath(path, paint);
     
    }

    canvas.drawTextOnPath:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
            @Override
            protectedvoidonDraw(Canvas canvas) {
     
                Path path =newPath();//定义一条路径
                path.moveTo(10,10);//移动到 坐标10,10
                path.lineTo(50,60);
                path.lineTo(200,80);
                path.lineTo(10,10);
     
    //          canvas.drawPath(path, paint);
                canvas.drawTextOnPath("Android777开发者博客", path,10,10, paint);
     
            }

     

    位置转换方法,canvas.rorate和canvas.translate:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    @Override
    protectedvoidonDraw(Canvas canvas) {
     
        paint.setAntiAlias(true);
        paint.setStyle(Style.STROKE);
        canvas.translate(canvas.getWidth()/2,200);//将位置移动画纸的坐标点:150,150
        canvas.drawCircle(0,0,100, paint);//画圆圈
     
        //使用path绘制路径文字
        canvas.save();
        canvas.translate(-75, -75);
        Path path =newPath();
        path.addArc(newRectF(0,0,150,150), -180, 180);
        Paint citePaint =newPaint(paint);
        citePaint.setTextSize(14);
        citePaint.setStrokeWidth(1);
        canvas.drawTextOnPath("http://www.android777.com", path,28,0, citePaint);
        canvas.restore();
     
        Paint tmpPaint =newPaint(paint);//小刻度画笔对象
        tmpPaint.setStrokeWidth(1);
     
        float y=100;
        intcount =60;//总刻度数
     
        for(inti=0; i <count ; i++){
            if(i%5==0){
                canvas.drawLine(0f, y,0, y+12f, paint);
                canvas.drawText(String.valueOf(i/5+1), -4f, y+25f, tmpPaint);
     
            }else{
                canvas.drawLine(0f, y, 0f, y +5f, tmpPaint);
            }
            canvas.rotate(360/count,0f,0f);//旋转画纸
        }
     
        //绘制指针
        tmpPaint.setColor(Color.GRAY);
        tmpPaint.setStrokeWidth(4);
        canvas.drawCircle(0,0,7, tmpPaint);
        tmpPaint.setStyle(Style.FILL);
        tmpPaint.setColor(Color.YELLOW);
        canvas.drawCircle(0,0,5, tmpPaint);
        canvas.drawLine(0,10,0, -65, paint);
     
    }


     

    上面几个例子基本已经将常用的canvas.draw*方法测试过了,我们结合一些事件,做一些有用户交互的应用:

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    packagecom.android777.demo.uicontroller.graphics;
     
    importjava.util.ArrayList;
     
    importandroid.app.Activity;
    importandroid.content.Context;
    importandroid.graphics.Canvas;
    importandroid.graphics.Color;
    importandroid.graphics.Paint;
    importandroid.graphics.PointF;
    importandroid.os.Bundle;
    importandroid.view.MotionEvent;
    importandroid.view.View;
     
    publicclassCanvasDemoActivityextendsActivity {
     
        @Override
        protectedvoidonCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
     
            setContentView(newCustomView1(this));
     
        }
     
        /**
         * 使用内部类 自定义一个简单的View
         * @author Administrator
         *
         */
        classCustomView1extendsView{
     
            Paint paint;
            privateArrayList<PointF> graphics =newArrayList<PointF>();
            PointF point;
     
            publicCustomView1(Context context) {
                super(context);
                paint =newPaint();//设置一个笔刷大小是3的黄色的画笔
                paint.setColor(Color.YELLOW);
                paint.setStrokeJoin(Paint.Join.ROUND);
                paint.setStrokeCap(Paint.Cap.ROUND);
                paint.setStrokeWidth(3);
     
            }
     
            @Override
            publicbooleanonTouchEvent(MotionEvent event) {
     
                graphics.add(newPointF(event.getX(),event.getY()));
     
                invalidate();//重新绘制区域
     
                returntrue;
            }
     
            //在这里我们将测试canvas提供的绘制图形方法
            @Override
            protectedvoidonDraw(Canvas canvas) {
                for(PointF point : graphics) {
                    canvas.drawPoint(point.x, point.y, paint);
                }
    //          super.onDraw(canvas);
     
            }
        }
     
    }

    当用户点击时将出现一个小点,拖动时将画出一条用细点组成的虚线:

    ——————————————————————————————————————

  89.  大家都知道在我们要显示一个自己定义的View有2中方法,第一种:是直接new 一个我们的View对象并且setContentView(myView); 假如我们自己定义的View对象叫myView  其实我们在Activity里边就2行代码就搞定了Java代码
    1. MyView myView = new MyView(this);  
    2.        setContentView(myView);  
    复制代码
    第二种方式就是 把它放到我们的布局文件中,例如这样<xiaohang.zhimeng.MyView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />
    其中xiaohang.zhimeng 是我们的包名。 用这种方式 必须在我们自定义的View类也就是MyView里边 加上这样个构造方法Java代码
    1. public MyView(Context context, AttributeSet attributeSet){  
    2.     super(context, attributeSet);  
    3. }  
    复制代码






    就是 一个图像旋转的例子 我们上代码吧。
    testActivity我们的Activity类
    Java代码
    1. package testView.moandroid;

    2. import android.app.Activity;
    3. import android.os.Bundle;

    4. public class testActivity extends Activity {
    5.         private testView mTestview;
    6.     /** Called when the activity is first created. */
    7.     @Override
    8.     public void onCreate(Bundle savedInstanceState) {
    9.         super.onCreate(savedInstanceState);
    10.         setContentView(R.layout.main);
    11.         mTestview = (testView) findViewById(R.id.testView);
    12.         mTestview.initBitmap(320,240,0xcccccc);
    13.     }
    14. }
    复制代码

    布局文件
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3. android:layout_width="fill_parent"
    4. android:layout_height="fill_parent">
    5. <testView.moandroid.testView
    6. android:id="@+id/testView"
    7. android:layout_width="fill_parent"
    8.      android:layout_height="fill_parent"
    9.      tileSize="12"/>
    10. </FrameLayout>
    复制代码



    testView类 这个类就是我们自己定义的View类了 这里我们把它放在布局文件中加载进来
    Java代码
    1. package testView.moandroid;

    2. import android.content.Context;
    3. import android.graphics.Bitmap;
    4. import android.graphics.Canvas;
    5. import android.graphics.Color;
    6. import android.graphics.Matrix;
    7. import android.graphics.Paint;
    8. import android.graphics.Typeface;
    9. import android.graphics.Bitmap.Config;
    10. import android.util.AttributeSet;
    11. import android.view.View;

    12. public class testView extends View {
    13.         private Bitmap mbmpTest = null;
    14.         private final Paint mPaint = new Paint();
    15.         private final String mstrTitle = "感受Android带给我们的新体验";

    16.         public testView(Context context, AttributeSet attrs, int defStyle) {
    17.                 super(context, attrs, defStyle);
    18.                 mPaint.setColor(Color.GREEN);
    19.         }

    20.         public testView(Context context, AttributeSet attrs) {
    21.                 super(context, attrs);
    22.                 mPaint.setColor(Color.GREEN);
    23.         }

    24.         public boolean initBitmap(int w, int h, int c) {
    25. //返回具有指定宽度和高度可变的位图,它的初始密度可以调用getDensity()
    26.                 mbmpTest = Bitmap.createBitmap(w, h, Config.ARGB_8888);
    27. //把一个具有指定的位图绘制到画布上。位图必须是可变的。
    28. //在画布最初的目标密度是与给定的位图的密度相同,返回一个具有指定位图的画布
    29.                 Canvas canvas = new Canvas(mbmpTest);
    30. //设置画布的颜色
    31.                 canvas.drawColor(Color.WHITE);
    32.                 Paint p = new Paint();
    33.                 String familyName = "宋体";
    34.                 Typeface font = Typeface.create(familyName, Typeface.BOLD);
    35.                 p.setColor(Color.RED);
    36.                 p.setTypeface(font);
    37.                 p.setTextSize(22);
    38. //0,100指定文字的起始位置
    39.                 canvas.drawText(mstrTitle, 0, 100, p);
    40.                 return true;
    41.         }

    42.         @Override
    43.         public void onDraw(Canvas canvas) {
    44.                 super.onDraw(canvas);
    45.                 if (mbmpTest != null) {
    46.                         Matrix matrix = new Matrix();
    47.                         // matrix.postScale(0.5f, 0.5f);
    48. //以 120,120这个点位圆心 旋转90度
    49.                         // matrix.setRotate(90,120,120);
    50. //使用指定的矩阵绘制位图
    51.                         canvas.drawBitmap(mbmpTest, matrix, mPaint);
    52.                 }
    53.         }
    54. }

    复制代码
    好了 我不知道 大家 看完这个例子 有没有什么不明白的地方? 或者哪里有疑问?为什么要这样? 我就说说我的疑问吧,我看完这个例子就有很多问题。大家都注意到了 我们的testView里边有一个initBitmap方法 还有这么一句Java代码
    1. canvas.drawText(mstrTitle, 0, 100, p);
    复制代码

    这个方法里边的 代码 请大家 一定要仔细 看看 我看完之后的疑问就是 我们在initBitmap方法里边不是都调用Java代码
    1. canvas.drawText(mstrTitle, 0, 100, p);
    复制代码

    把文字画到屏幕上了吗 ?为什么还要到 onDraw里边在指定位图再画一次 ? 刚开始晕的不行 我不知道这是为什么 在这里我就不贴代码了 其实大家可以试试的 比如我自己定义一方法 我把所有的画图操作都放到我自己定义的方法里边来,我在自己 new 一个Canvas对象 并且调用它的drawBitmap 绘制位图 试试看。我就不用onDraw方法来画图。我也不用onDraw方法提供的 canvas对象。这里我就不演示了 大家 尽管自己疯狂的试试吧。 我想结果肯定是 不是异常,就是图画不出来 前提是你得用 自己 new 一个Canvas对象。就是你得用自己new 的Canvas对象去调用drawBitmap方法。

        那我为什么用自己定义的 Canvas对象就不能画出图来呢? 不知道我的意思表达清楚没有,这里 我觉得一定得多试试 了不然没体会的。其实大家可以多看看 不管是我博客的例子还是网上的例子 或者书上的例子,其实我也才学android不久 你就会发现 所有的 画图不管是简单的 花一些 几何图像 ,长方形,圆形啊。 还是 一些 图片的 旋转缩放操作啊,这些操作我的 博客里边也有  我们应该注意到它们用的都是 Draw方法提供的那个 Canvas对象。 像上边 mo-android的那个例子 它虽然 new 了一个Canvas 但是最后还得去 onDraw方法里边 用onDraw方法提供的那个 canvas对象 调用drawBitmap方法来显示位图 而这个位图恰恰是与 刚才new 的那个Canvas对象关联的。这里先给大家看几个方法吧,就是觉得应该知道或者得注意一下。
    Java代码
    1. Public Canvas(Bitmap bitmap)
    复制代码
    构建一个具有指定位图绘制到画布上。位图必须是可变的。在画布最初的密度是与给定的位图的密度相同,这就是Canvas类的一个构造方法没什么,这里提示一下它需要的是一个 可变的位图。 下一个

    Java代码
    1. Public void setBitmap(Bitmap bitmap)
    复制代码

    此方法说明:指定一个可变的位图绘制到画布,画图的密度匹配位图,这也是Canvas的一个方法 也是需要一个可变的位图。

    Java代码
    1. public final boolean isMutable ()
    复制代码
    Bitmap有这样一个方法来判断位图是否可变 如果可变返回值为true

    Java代码
    1. Bitmap bitmap = Bitmap.createBitmap(160, 250, Config.ARGB_8888);
    复制代码
    createBitmap是Bitmap类的一个静态方法 它返回的也是一个 可变的位图。我为什么这样说呢 ?因为有图为证


    Bitmap的源码里有这样一个变量Java代码
    1. private final boolean mIsMutable;
    复制代码
    大家注意看一下图中的mIsMutable  的值 为true 刚才上边已经说了Bitmap有一个isMutable方法可以判断一个位图是否为可变 值为true说明是可变的。

    上边那个疑问,我想大家都还记得。我也在网上查了查,首先必须告诉大家我们的Canvas 类里边有 这样两个对象大家可以打开这个类的源码看看。。
    Java代码
    1. private Bitmap  mBitmap;    // if not null, mGL must be null
    2. private GL      mGL;
    复制代码
    在android 有这样一个概念 就是 native canvas 这里就不翻译了,不知道叫啥好。(比如什么母画布或者本地画布) 我们的native canvas 可以是屏面或者是 GL 或者 图片画布。如果是屏面,我们的GL对象 mGL将是null, mBitmap可能会也可能不会 目前(我们的默认构造方法创建一个画布,但是这个画布没有屏面) 也就是说如果你这样创建一个画布
    Canvas canvas = new Canvas();  这时候这个canvas 对象 将没有屏面 也没有 java-bitmap 可以理解为java的位图 。 如果我们是以Gl 为 基础(native canvas),然后mBitmap将是空的,mGl不能为空。因此这2个对象 不可能都是非空的 因为这2个对象只要有一个不为空,另外的一个就得为空。但是有可能两个都为空。如下图



      所以我觉得那个onDraw(Canvas canvas)方法里边的那个Canvas对象和我们自己new的是有区别的,大家可以在试试 直接 用onDraw方法里边的 Canvas对象 调用 宽度和高度试试
    canvas.getWidth   canvas.getHeight  得到的 是 320 和 480 也就是我屏幕的高和宽。如果你自己定义 new 一个 Canvas  这样 Canvas canvas = new Canvas()  你在用这个canvas调用高度和宽度 试试看, 我试了一下我发现者 调用高度和宽度后边的代码都不会执行了,很是奇怪呵呵,下面在来一点 关于UI的说明,参考了Android native draw
       
       在 Android 上,有一個 graphic engine ,称为 Skia 。 Skia 的功能约等于 Cairo ,功能上相似,但 Skia 没有支持 Cairo, Android 的 Java Code 都是透過 Skia 进行绘图,而 Skia 主要的 class type 是 SkCanvas ,所的有绘图功能都建立在这个 class 上。因此,如果我們能在 native code 取得 Android 所建立的 SkCanvas ,能直接使用 Skia 对画面做輸出。

         在 Android 的 UI 设计里,每一個 UI component 都是一個 view ;例如: button 、 label 等等,全是 view 。当Android 要画一个view 時,会呼叫 view 的 onDraw() 画出 component 的外觀。而 Android 会将一個 android.graphics.Canvas type 的物件,当成参数給 onDraw() 。 onDraw() 就在这个 canvas 上输出 component 的外观,例如画一个button 。这个 canvas 其实就对映到一个 SkCanvas ,我们只要在这个 canvas 上作画,就等于画到画面上的一个区域。

      今天又正好看到杨丰盛老师的 双缓冲的例子 我在这里把那个自定义的View类贴出来
    Java代码
    1. package com.yarin.android.Examples_05_12;

    2. import android.content.Context;
    3. import android.graphics.Bitmap;
    4. import android.graphics.Canvas;
    5. import android.graphics.Paint;
    6. import android.graphics.Bitmap.Config;
    7. import android.graphics.drawable.BitmapDrawable;
    8. import android.view.KeyEvent;
    9. import android.view.MotionEvent;
    10. import android.view.View;

    11. public class GameView extends View implements Runnable
    12. {
    13.         /* 声明Bitmap对象 */
    14.         Bitmap        mBitQQ        = null;
    15.        
    16.         Paint   mPaint = null;
    17.        
    18.         /* 创建一个缓冲区 */
    19.         Bitmap        mSCBitmap = null;
    20.        
    21.         /* 创建Canvas对象 */
    22.         Canvas mCanvas = null;   
    23.        
    24.         public GameView(Context context)
    25.         {
    26.                 super(context);
    27.                
    28.                 /* 装载资源 */
    29.                 mBitQQ = ((BitmapDrawable) getResources().getDrawable(R.drawable.qq)).getBitmap();
    30.                
    31.                 /* 创建屏幕大小的缓冲区 */
    32.                 mSCBitmap=Bitmap.createBitmap(320, 480, Config.ARGB_8888);  
    33.                
    34.                 /* 创建Canvas */
    35.                 mCanvas = new Canvas();  
    36.                
    37.                 /* 设置将内容绘制在mSCBitmap上 */
    38.                 mCanvas.setBitmap(mSCBitmap);
    39.                
    40.                 mPaint = new Paint();
    41.                
    42.                 /* 将mBitQQ绘制到mSCBitmap上 */
    43.                 mCanvas.drawBitmap(mBitQQ, 0, 0, mPaint);
    44.                
    45.                 /* 开启线程 */
    46.                 new Thread(this).start();
    47.         }
    48.        
    49.         public void onDraw(Canvas canvas)
    50.         {
    51.                 super.onDraw(canvas);
    52.                
    53.                 /* 将mSCBitmap显示到屏幕上 */
    54.                 canvas.drawBitmap(mSCBitmap, 0, 0, mPaint);
    55.         }
    56.        
    57.         // 触笔事件
    58.         public boolean onTouchEvent(MotionEvent event)
    59.         {
    60.                 return true;
    61.         }


    62.         // 按键按下事件
    63.         public boolean onKeyDown(int keyCode, KeyEvent event)
    64.         {
    65.                 return true;
    66.         }


    67.         // 按键弹起事件
    68.         public boolean onKeyUp(int keyCode, KeyEvent event)
    69.         {
    70.                 return false;
    71.         }


    72.         public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)
    73.         {
    74.                 return true;
    75.         }
    76.        
    77.        
    78.         /**
    79.          * 线程处理
    80.          */
    81.         public void run()
    82.         {
    83.                 while (!Thread.currentThread().isInterrupted())
    84.                 {
    85.                         try
    86.                         {
    87.                                 Thread.sleep(100);
    88.                         }
    89.                         catch (InterruptedException e)
    90.                         {
    91.                                 Thread.currentThread().interrupt();
    92.                         }
    93.                         //使用postInvalidate可以直接在线程中更新界面
    94.                         postInvalidate();
    95.                 }
    96.         }
    97. }

    复制代码

    首先先不说它有没有双缓冲,好像没有但是又有点那个意思。 呵呵。请大家注意看这个类的构造方法吧 然后再和上边 moandroid那个例子 对比 看看有没有什么相似的地方。我看到这例子和看到上边那个例子 的疑问 一样 就是 在 GameView类里边我们已经 执行了
    Java代码
    1. /* 将mBitQQ绘制到mSCBitmap上 */
    2.                 mCanvas.drawBitmap(mBitQQ, 0, 0, mPaint);

    复制代码
    这句 为什么 又跑到 onDraw方法 指定位图然后显示到屏幕上。 呵呵。发现论坛上也有一些人 困惑这里。 希望高手能表达一下观点,最好整理一篇文章出来 呵呵,让我们这些新学的菜鸟 更明白些。期待大家自由表达自己的观点。
  90. ——————————————————————————————————————————————————————
    1. public class MySurfaceView extends SurfaceView implements Callback, Runnable {  
    2.     //用于控制SurfaceView  
    3.     private SurfaceHolder sfh;  
    4.     //声明一个画笔  
    5.     private Paint paint;  
    6.     //声明一条线程  
    7.     private Thread th;  
    8.     //线程消亡的标识位  
    9.     private boolean flag;  
    10.     //声明一个画布  
    11.     private Canvas canvas;  
    12.     //声明屏幕的宽高  
    13.     private int screenW, screenH;  
    14.     //设置画布绘图无锯齿  
    15.     private PaintFlagsDrawFilter pfd = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);  
    16.     /** 
    17.      * SurfaceView初始化函数 
    18.      */  
    19.     public MySurfaceView(Context context) {  
    20.         super(context);  
    21.         //实例SurfaceHolder  
    22.         sfh = this.getHolder();  
    23.         //为SurfaceView添加状态监听  
    24.         sfh.addCallback(this);  
    25.         //实例一个画笔  
    26.         paint = new Paint();  
    27.         //设置画笔颜色为白色  
    28.         paint.setColor(Color.WHITE);  
    29.         //设置焦点  
    30.         setFocusable(true);  
    31.     }  
    32.   
    33.     /** 
    34.      * SurfaceView视图创建,响应此函数 
    35.      */  
    36.     @Override  
    37.     public void surfaceCreated(SurfaceHolder holder) {  
    38.         screenW = this.getWidth();  
    39.         screenH = this.getHeight();  
    40.         flag = true;  
    41.         //实例线程  
    42.         th = new Thread(this);  
    43.         //启动线程  
    44.         th.start();  
    45.     }  
    46.   
    47.     /** 
    48.      * 游戏绘图 
    49.      */  
    50. public void myDraw() {  
    51.     try {  
    52.         canvas = sfh.lockCanvas();  
    53.         if (canvas != null) {  
    54.             //----设置画布绘图无锯齿  
    55.             canvas.setDrawFilter(pfd);  
    56.             //----利用填充画布,刷屏  
    57.             canvas.drawColor(Color.BLACK);  
    58.             //----绘制文本  
    59.             canvas.drawText("drawText"1010, paint);  
    60.             //----绘制像素点  
    61.             canvas.drawPoint(1020, paint);  
    62.             //----绘制多个像素点  
    63.             canvas.drawPoints(new float[] { 10303030 }, paint);  
    64.             //----绘制直线  
    65.             canvas.drawLine(10405040, paint);  
    66.             //----绘制多条直线  
    67.             canvas.drawLines(new float[] { 10505050705011050 }, paint);  
    68.             //----绘制矩形  
    69.             canvas.drawRect(106040100, paint);  
    70.             //----绘制矩形2  
    71.             Rect rect = new Rect(1011060130);  
    72.             canvas.drawRect(rect, paint);  
    73.             canvas.drawRect(rect, paint);  
    74.             //----绘制圆角矩形  
    75.             RectF rectF = new RectF(1014060170);  
    76.             canvas.drawRoundRect(rectF, 2020, paint);  
    77.             //----绘制圆形  
    78.             canvas.drawCircle(2020020, paint);  
    79.             //----绘制弧形  
    80.             canvas.drawArc(new RectF(1502020070), 0230true, paint);  
    81.             //----绘制椭圆  
    82.             canvas.drawOval(new RectF(15080180100), paint);  
    83.             //----绘制指定路径图形  
    84.             Path path = new Path();  
    85.             //设置路径起点  
    86.             path.moveTo(160150);  
    87.             //路线1  
    88.             path.lineTo(200150);  
    89.             //路线2  
    90.             path.lineTo(180200);  
    91.             //路径结束  
    92.             path.close();  
    93.             canvas.drawPath(path, paint);  
    94.             //----绘制指定路径图形  
    95.             Path pathCircle = new Path();  
    96.             //添加一个圆形的路径  
    97.             pathCircle.addCircle(13026020, Path.Direction.CCW);  
    98.             //----绘制带圆形的路径文本  
    99.             canvas.drawTextOnPath("PathText", pathCircle, 1020, paint);  
    100.         }  
    101.     } catch (Exception e) {  
    102.         // TODO: handle exception  
    103.     } finally {  
    104.         if (canvas != null)  
    105.             sfh.unlockCanvasAndPost(canvas);  
    106.     }  
    107. }  
    108.   
    109.     /** 
    110.      * 触屏事件监听 
    111.      */  
    112.     @Override  
    113.     public boolean onTouchEvent(MotionEvent event) {  
    114.         return true;  
    115.     }  
    116.   
    117.     /** 
    118.      * 按键事件监听 
    119.      */  
    120.     @Override  
    121.     public boolean onKeyDown(int keyCode, KeyEvent event) {  
    122.         return super.onKeyDown(keyCode, event);  
    123.     }  
    124.   
    125.   
    126.     @Override  
    127.     public void run() {  
    128.         while (flag) {  
    129.             long start = System.currentTimeMillis();  
    130.             myDraw();  
    131.             long end = System.currentTimeMillis();  
    132.             try {  
    133.                 if (end - start < 50) {  
    134.                     Thread.sleep(50 - (end - start));  
    135.                 }  
    136.             } catch (InterruptedException e) {  
    137.                 e.printStackTrace();  
    138.             }  
    139.         }  
    140.     }  
    141.   
    142.     /** 
    143.      * SurfaceView视图状态发生改变,响应此函数 
    144.      */  
    145.     @Override  
    146.     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {  
    147.     }  
    148.   
    149.     /** 
    150.      * SurfaceView视图消亡时,响应此函数 
    151.      */  
    152.     @Override  
    153.     public void surfaceDestroyed(SurfaceHolder holder) {  
    154.         flag = false;  
    155.     } 
  91. ————————————————————————————————————————————————————————————
  92.   方法一:
      给Paint加上抗锯齿标志。然后将Paint对象作为参数传给canvas的绘制方法。
      paint.setAntiAlias(true);

      方法二:
      给Canvas加上抗锯齿标志。有些地方不能用paint的,就直接给canvas加抗锯齿,更方便。
      canvas.setDrawFilter(new PaintFlagsDrawFilte(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));

      调整Activity中自定义视图(View)的大小

      view本身响应onMeasure事件:
      protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec){
          int height = View.MeasureSpec.getSize(heightMeasureSpec);
          int width = View.MeasureSpec.getSize(widthMeasureSpec);
          setMeasuredDimension(width,height);  //这里面是原始的大小,需要重新计算可以修改本行
      }

      view所在的activity调用改view大小:
      LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) mView.getLayoutParams();
      linearParams.height = 400;
      mView.setLayoutParams(linearParams);

      禁止屏幕随手机旋转变化

      在AndroidManifest.xml的每一个需要禁止转向的Activity配置中加入android:screenOrientation="landscape"属性。
      landscape = 横向,portrait = 纵向

      避免在转屏时重启Activity

      每次屏幕方向切换Android都会重启Activity,一种方法是在Activity销毁前保存当前的状态,在Activity再次创建的时候恢复状态;
      第二种方法是避免在转屏时重启Activity,可以通过在AndroidManifest.xml文件中重新定义方向。
      (给每个Activity加上android:configChanges="keyboardHidden|orientation")
      然后在需要控制屏幕显示方向的Activity中重写onConfigurationChanged(Configuration newConfig)方法,这样在转屏时就不会重启Activity了,转为发送事件让Activity自己处理。比如:

      if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){
          setContentView(R.layout.file_list_landscape);//横向
      }else{
          setContentView(R.layout.file_list);//竖向
      }

      在模拟器中可以按 CTL+F11 模拟做屏幕旋转。

      启动一个程序

      Intent intent=new Intent();
      intent.setComponent(new ComponentName(
          "com.android.calendar", "com.android.calendar.LaunchActivity"));
      startActivity(intent);

      格式化日期使用SimpleDateFormat

      String format = "MMM dd yyyy";
      SimpleDateFormat sdf = new SimpleDateFormat(format);
      titleText=sdf.format(c.getTime());

      获取屏幕分辨率

      Display display = getWindowManager().getDefaultDisplay();
      display.getWidth();

      获取XML中的资源

      String[] countries = getResources().getStringArray(R.array.countries_array);
      getResources().getDrawable();


0 0
原创粉丝点击