本文参考文献:《疯狂Android讲义 : 第2版 》

虽然前面大量介绍了使用自定义 View 来进行绘图,但 View 的绘图机制存在如下缺陷:

  1. View 缺乏双缓冲机制;
  2. 当程序需要更新 View 上的图像时,程序必须重绘 View 上显示的整张图片;
  3. 新线程无法直接更新 View 组件。

由于 View 存在上述缺陷,所以通过自定义 View 来实现绘图,尤其是游戏中的绘图时性能并不好。Android 提供了一个 SurfaceView 来代替 View,在实现游戏绘图方面,SurfaceView 比 View 更加出色,因此一般推荐使用 SurfaceView。

布局文件的内容如下:

<?xml version="1.0" encoding="utf-8"?>    

主程序文件的代码如下:

package com.toby.personal.testlistview;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.MotionEvent;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;public class MainActivity extends AppCompatActivity {    final private static String TAG = "Toby_Test";    private SurfaceHolder holder;    private Paint paint;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        paint = new Paint();        SurfaceView surface = (SurfaceView) findViewById(R.id.show);        holder = surface.getHolder();        holder.addCallback(new SurfaceHolder.Callback() {            @Override            public void surfaceCreated(SurfaceHolder holder) {                Canvas canvas = holder.lockCanvas();                Bitmap back = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.drawable.plane);                canvas.drawBitmap(back, 0, 0, null);                holder.unlockCanvasAndPost(canvas);                holder.lockCanvas(new Rect(0, 0, 0, 0));                holder.unlockCanvasAndPost(canvas);            }            @Override            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {            }            @Override            public void surfaceDestroyed(SurfaceHolder holder) {            }        });        surface.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                if (event.getAction() == MotionEvent.ACTION_DOWN) {                    int cx = (int) event.getX();                    int cy = (int) event.getY();                    Canvas canvas = holder.lockCanvas(new Rect(cx - 50, cy - 50, cx + 50, cy + 50));                    canvas.save();                    canvas.rotate(30, cx, cy);                    paint.setColor(Color.RED);                    canvas.drawRect(cx - 40, cy - 40, cx, cy, paint);                    canvas.restore();                    paint.setColor(Color.GREEN);                    canvas.drawRect(cx, cy, cx + 40, cy + 40, paint);                    holder.unlockCanvasAndPost(canvas);                }                return false;            }        });    }}

实例:基于 SurfaceView 开发示波器

SurfaceView 与普通 View 还有一个重要的区别:View 的绘图必须在当前 UI 线程中进行;但是 SurfaceView 是由 SurfaceHolder 来完成的。这样就避免了阻塞主线程。

下面是主布局代码的内容:

<?xml version="1.0" encoding="utf-8"?>            

主程序文件的代码如下:

package com.toby.personal.testlistview;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import java.util.Timer;import java.util.TimerTask;public class MainActivity extends AppCompatActivity {    final private static String TAG = "Toby_Test";    private SurfaceHolder holder;    private Paint paint;    final int HEIGHT = 320;    final int WIDTH = 640;    final int X_OFFSET = 40;    private int cx = X_OFFSET;    int centerY = HEIGHT / 2;    Timer timer = new Timer();    TimerTask task = null;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        final SurfaceView surface = (SurfaceView) findViewById(R.id.show);        holder = surface.getHolder();        paint = new Paint();        paint.setStrokeWidth(3);        holder.addCallback(new SurfaceHolder.Callback() {            @Override            public void surfaceCreated(SurfaceHolder holder) {            }            @Override            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {                drawBack(holder);            }            @Override            public void surfaceDestroyed(SurfaceHolder holder) {                timer.cancel();            }        });    }    private void drawBack(SurfaceHolder holder) {        Canvas canvas = holder.lockCanvas();        canvas.drawColor(Color.GRAY);        Paint p = new Paint();        p.setColor(Color.BLACK);        p.setStrokeWidth(3);        canvas.drawLine(X_OFFSET, centerY, WIDTH, centerY, p);        canvas.drawLine(X_OFFSET, 40, X_OFFSET, HEIGHT, p);        holder.unlockCanvasAndPost(canvas);        holder.lockCanvas(new Rect(0, 0, 0, 0));        holder.unlockCanvasAndPost(canvas);    }    public void drawSinLine(View view) {        doDraw(view);    }    private void doDraw(final View source) {        drawBack(holder);        cx = X_OFFSET;        if (task != null) {            task.cancel();        }        task = new TimerTask() {            @Override            public void run() {                final double radian = (cx - X_OFFSET) * 2 * Math.PI / 150;                final int cy = source.getId() == R.id.sin                        ? centerY - (int) (100 * Math.sin(radian))                        : centerY - (int) (100 * Math.cos(radian));                paint.setColor(source.getId() == R.id.sin ? Color.GREEN : Color.RED);                Canvas canvas = holder.lockCanvas(new Rect(cx, cy - 2, cx + 2, cy + 2));                canvas.drawPoint(cx, cy, paint);                cx++;                if (cx > WIDTH) {                    task.cancel();                    task = null;                }                holder.unlockCanvasAndPost(canvas);            }        };        timer.schedule(task, 0, 30);    }    public void drawCosLine(View view) {        doDraw(view);    }}

该示例的运行效果如下:

显示效果

更多相关文章

  1. 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
  2. 一款常用的 Squid 日志分析工具
  3. GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
  4. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  5. Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
  6. Android(安卓)NDK下编译google protocol buffer(protobuf)
  7. Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
  8. android apk反编译到java源码的实现方法
  9. 在/data/下创建文件的权限问题

随机推荐

  1. 更改Android AVD模拟器创建路径位置的方
  2. Android高手进阶教程(十一)之----Android
  3. Android中关于android:imeOptions="actio
  4. Android(安卓)上层应用读写设备节点
  5. Android(安卓)Studio导入SlidingMenu类库
  6. linux公社大量免费的在线android资料
  7. 处女男学Android(十五)---Android 广播机制
  8. 总结系列-硬件加速
  9. Android音频开发(1):基础知识
  10. fir.im Weekly - 如何进行 Android(安卓)