第六章 一张白纸好作画—Canvas画布(1)

第六章 一张白纸好作画—Canvas画布

前面的相关章节,我们详细说明过Android UI组件的使用。通过前面章节的学习,开发者已经可以开发出令人满意的UI效果了。但是有的时候,我们需要实现更加漂亮的UI效果,此时可能就无法直接使用UI组件,而是需要自己画出各种UI效果了。

在Android中,Canvas就是一个画布,开发者可以在画布上绘制想要的任何东西。在本章中,我们将介绍Canvas及相关的技术。

6.1 Canvas画布介绍

6.1.1View Canvas—使用普通View的Canvas画图

从J2ME MIDLET时我们就知道Java提供了Canvas类,而目前在Android平台中,它主要任务为管理绘制过程, 就像一个画布,任何的绘画都将在这个画布上完成。

Canvas类有三个构造方法,分别为构造一个空的Canvas,从Bitmap中构造(2D)和从GL对象中创建(3D),具体如下:

Canvas();//一般使用在View中的Canvas

Canvas(Bitmap bitmap);//从2D对象中创建

Canvas(GL gl); //从3D对象中创建

 

由于Java先天的一些问题,基于设备硬件的处理速度考虑,3D的应用更多的需要使用C++的底层库来实现,这样才能有更好的用户体验。这里我们将重点介绍的是Canvas在2D中的功能。

先来看如何使用普通View的Canvas画图。

一般的,操作步骤如下:

1)定义一个自己的View :class your_view extends View{}。

2)重载View的onDraw方法:protectedvoid onDraw(Canvas canvas){}。

3)在onDraw方法中定义你自己的画图操作。

4)在代码或布局文件中使用。

例如:我们可以实现一个带边框文字的textview。代码片段如下所示。

// import略

public class ShadeTextView extends TextView {

    public ShadeTextView(Context context, AttributeSet attrs) {

        super(context, attrs);

    }

    @Override

    public void onDraw(Canvas canvas) {

        super.onDraw(canvas);

        drawText(canvas, 0xffff0000);

        super.onDraw(canvas);

    }  

    // 注:这里只做了单行的字处理

    private void drawText( Canvas canvas, int bg) {

        Paint paint = getPaint();

        // 获取textview的文本

        String text = String.valueOf(getText());

        // 获取第一行文字的左边距

        float startX = getLayout().getLineLeft(0);

        // 获取第一行文字的底部距离

float startY =  getBaseline() ;

        paint.setColor(bg); 

        canvas.drawText(text, startX + 1 , startY, paint);  

        canvas.drawText(text, startX, startY - 1 , paint);  

        canvas.drawText(text, startX, startY + 1 , paint);  

        canvas.drawText(text, startX - 1 , startY, paint);  

    }

}

 

在布局文件中使用:

<com.yourpackage.ShadeTextView

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text=" 测试带阴影的文字"

    android:textSize="20sp"/>

 

图6-1 带边框TextView的实现结果

 

在这里,我们新建了一个类ShadeTextView,继承自TextView类,重写了onDraw(Canvas canvas)方法,在这个方法里画出了边框。

6.1.2 Bitmap Canvas—使用普通Bitmap的Canvas画图

我们也可以定义自己的Bitmap,然后生成一个属于这个Bitmap的Canvas,并在其上进行你需要的绘画。最终可以自由的使用这个图片。

这种方式,主要用于自定义的绘制图形,和刷新比较快的、需要进行双缓冲防止闪屏的场合。

代码示例如下。

Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);

// 必须将这个Bitmap放入View的Canvas中,画的图才会被显示出来

Canvas c = new Canvas(b);

6.1.3SurfaceView Canvas—使用SurfaceView的Canvas画图

前面看到如何使用普通View的Canvas画图和普通的图片的Canvas,Android为方便我们使用View的Canvas进行画图还封装一个类SurfaceView。SurfaceView方式和View方式的主要区别在于:SurfaceView中定义了一个专门的线程来完成画图工作,应用程序不需要等待View的刷图,提高了性能。View的方式适合处理量比较小,帧率比较小的动画,比如说象棋游戏之类的;而SurfaceView方式主要用在游戏,高品质动画方面的画图。

使用SurfaceView,一般步骤如下:

1)定义一个自己的SurfaceView:class your_SurfaceView extends extendsSurfaceView implements SurfaceHolder.Callback() {}

2)实现SurfaceHolder.Callback的3个方法:surfaceCreated()、surfaceChanged()、surfaceDestroyed()

3)定义自己的专注于画图的线程:class your_thread extends Thread

4)重载线程的run()函数(在SurfaceView 的surfaceCreated()中启动这个线程)

下面的示例代码详细说明了线程的处理过程。

// import略

public class YourViewThread extends Thread{

 

    // 睡眠的毫秒数

    private int sleepSpan = 100;

    // 循环标记位

private boolean flag = false;

// 游戏界面的引用

    private YourSurfaceView mYourSurfaceView;

    private SurfaceHolder mSurfaceHolder = null; 

   

    public YourViewThread (YourSurfaceView mYourSurfaceView , SurfaceHolder mSurfaceHolder){

        this. mYourSurfaceView = mYourSurfaceView;

        this.mSurfaceHolder = mSurfaceHolder;

    }

    public void run(){

        // 画布

        Canvas c;

        while(flag) {

             c = null;

             try {

                 // 锁定整个画布,在内存要求比较高的情况下,建议参数不要为null

                 c = mSurfaceHolder.lockCanvas(null);

                 synchronized (this.mSurfaceHolder) {

                     try{

                          mYourSurfaceView.onDraw(c);

                     } catch(Exception e) { }

                 }

             } finally {

                 if (c != null) {

                     // 更新屏幕显示内容

                     mSurfaceHolder.unlockCanvasAndPost(c);

                 }

             }

             try {

                // 睡眠sleepSpan毫秒

                 Thread.sleep(sleepSpan);

             } catch(Exception e) { }

        }

    }

 

public void setFlag(boolean flag) {

    // 设置循环标记

        this.flag = flag;

    }  

}

 

--------------------------------------------
程序员赚钱不易 一定要学会理财
平安陆金所 隶属于平安集团的p2p平台
年投资回报率7%-9% 是替代银行理财的首选
个人经验 推荐投资安鑫或者有担保的彩虹项目
不要投资安e 那个几乎无法转让 想提前提现非常困难
首次投资1000元即可额外赚几百元 不赚白不赚
--------------------------------------------

下面的示例代码详细说明了画图的过程。

// import略

public class YourSurfaceView extends SurfaceView

    implements SurfaceHolder.Callback{

 

    private YourViewThread mYourViewThread;

 

    public YourSurfaceView(Activity activity) {

        super(activity);

        // 将SurfaceView画布的句柄传给刷新线程

        mYourViewThread = new YourViewThread(this,getHolder());   

        getHolder().addCallback(this);

    }

 

    protected void onDraw(Canvas canvas) {

        if(canvas == null) {

             return;

        }

    }

 

    @Override

    public boolean onTouchEvent(MotionEvent event){

        return true;

    }

 

    @Override

    public boolean onKeyDown(int keyCode,KeyEvent event){

        return false;

    }

 

    @Override

    public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {

        // 当画布发生变化的时候会自动调用

    }

 

    @Override

    public void surfaceCreated(SurfaceHolder holder) {

        // 当画布被创建的时候会自动调用

         try{

                 // 启动刷新线程

                 mYourViewThread.setFlag(true);

                 mYourViewThread.start();

            } catch(Exception ex){

                mYourViewThread = new YourViewThread(this,getHolder());

                mYourViewThread.setFlag(true);

                mYourViewThread.start();

            }

    }

 

    @Override

    public void surfaceDestroyed(SurfaceHolder holder) {

        // 当画布被销毁的时候会自动调用

        boolean retry = true;

        mYourViewThread.setFlag(false);

        while (retry) {

            try {

            mYourViewThread.join();

                retry = false;

            } catch (InterruptedException e) {

            }

        }

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值