一、SurfaceView的介绍

在前面我们已经会自定义View,使用canvas绘图,但是View的绘图机制存在一些缺陷。

1、View缺乏双缓冲机制。

2、程序必须重绘整个View上显示的图片,比较耗资源。

3、非UI线程无法更新View组件,所以会占用主线程资源,当需要在主线程中处理逻辑的时候会很慢。

在Android中为我们提供了一个SurfaceView来替代View实现绘制图形,一般在游戏绘图方面应用较广,所以如果是比较复杂的绘图建议使用SurfaceView.

二、SurfaceView的绘图机制

SurfaceView一般会与SurfaceHolder结合使用,SurfaceHolder用于与之关联的SurfaceView上绘图,调用SurfaceView的getHolder()方法可获取SurfaceView关联的SurfaceHolder.
SurfaceHolder提供了lockCanvas和lockCanvas(Rect dirty)来锁定绘图区域,并获取到该区域的画布(Canvas)我们通过该画布就可以进行图形的绘制了。

三、SurfaceView使用实例

1、一个简单的使用(绘制在UI线程)
package com.test.surfaceview;

import android.app.Activity;
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.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener; import com.example.testsurfaceview.R; public class MainActivity extends Activity{ private SurfaceHolder holder;
private Paint paint;
private Rect rect; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); paint = new Paint();
rect = new Rect(); SurfaceView surface = (SurfaceView)findViewById(R.id.show);
holder = surface.getHolder(); //由系统毁掉的三个函数
holder.addCallback(new SurfaceHolder.Callback() { @Override
public void surfaceDestroyed(SurfaceHolder holder) {
} @Override
public void surfaceCreated(SurfaceHolder holder) {
Canvas canvas = holder.lockCanvas();
Bitmap bitmap = BitmapFactory.decodeResource(
MainActivity.this.getResources(), R.drawable.ic_launcher);
canvas.drawBitmap(bitmap, 0, 0, null);
holder.unlockCanvasAndPost(canvas);
} @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
}); //绑定事件监听
surface.setOnTouchListener(new 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(); rect.set(cx - 50, cy - 50, cx + 50, cy + 50);
//锁定一个固定区域并锁定
Canvas canvas = holder.lockCanvas(rect);
//保存画布当前状态
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;
}
});
}
}

2、在非UI线程中绘制

package com.test.surfaceview;

import android.content.Context;
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.AsyncTask;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView; import com.example.testsurfaceview.R; /**
* 阳光小强 http://blog.csdn.net/dawanganban
*
* @author Administrator
*
*/
public class MySurfaceView extends SurfaceView { private Context context;
private Rect rect;
private Paint paint; private AppStartDrawView appStartDrawView; public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
rect = new Rect();
paint = new Paint();
appStartDrawView = new AppStartDrawView();
this.getHolder().addCallback(appStartDrawView);
} /**
* 停止动画
*/
public void stopAnim() {
appStartDrawView.cancel(true);
} private class AppStartDrawView extends AsyncTask<Void, Integer, Void> implements SurfaceHolder.Callback {
private boolean isStarted = false;
private SurfaceHolder holder; @Override
public void surfaceCreated(SurfaceHolder holder) {
this.holder = holder; //绘制一个图片
Canvas canvas = holder.lockCanvas();
Bitmap bitmap = BitmapFactory.decodeResource(
context.getResources(), R.drawable.ic_launcher);
canvas.drawBitmap(bitmap, 0, 0, null);
holder.unlockCanvasAndPost(canvas); if (!isStarted) {
this.execute();
isStarted = true;
}
} @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
this.holder = holder;
} @Override
public void surfaceDestroyed(SurfaceHolder holder) {
isStarted = false;
holder = null;
} @Override
protected Void doInBackground(Void... params) {
int cx = 0;
int cy = 0;
while(!isCancelled()){
//绘制动画
//TODO .....
rect.set(cx - 50, cy - 50, cx + 50, cy + 50);
//锁定一个固定区域并锁定
Canvas canvas = holder.lockCanvas(rect);
//保存画布当前状态
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); //TODO ....
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cx += 60;
cy += 60; if(cx >= 400){
stopAnim();
}
}
return null;
} }
}

Android自定义组件系列【12】——非UI线程绘图SurfaceView的更多相关文章

  1. Android自定义组件系列【7】——进阶实践(4)

    上一篇<Android自定义组件系列[6]--进阶实践(3)>中补充了关于Android中事件分发的过程知识,这一篇我们接着来分析任老师的<可下拉的PinnedHeaderExpan ...

  2. Android自定义组件系列【6】——进阶实践(3)

    上一篇<Android自定义组件系列[5]--进阶实践(2)>继续对任老师的<可下拉的PinnedHeaderExpandableListView的实现>进行了分析,这一篇计划 ...

  3. Android自定义组件系列【5】——进阶实践(2)

    上一篇<Android自定义组件系列[5]--进阶实践(1)>中对任老师的<可下拉的PinnedHeaderExpandableListView的实现>前一部分进行了实现,这一 ...

  4. Android自定义组件系列【4】——自定义ViewGroup实现双侧滑动

    在上一篇文章<Android自定义组件系列[3]--自定义ViewGroup实现侧滑>中实现了仿Facebook和人人网的侧滑效果,这一篇我们将接着上一篇来实现双面滑动的效果. 1.布局示 ...

  5. Android自定义组件系列【5】——进阶实践(1)

    接下来几篇文章将对任老师的博文<可下拉的PinnedHeaderExpandableListView的实现>分步骤来详细实现,来学习一下大神的代码并记录一下. 原文出处:http://bl ...

  6. Android自定义组件系列【3】——自定义ViewGroup实现侧滑

    有关自定义ViewGroup的文章已经很多了,我为什么写这篇文章,对于初学者或者对自定义组件比较生疏的朋友虽然可以拿来主义的用了,但是要一步一步的实现和了解其中的过程和原理才能真真脱离别人的代码,举一 ...

  7. Android自定义组件系列【8】——遮罩文字动画

    遮罩文字的动画我们在Flash中非常常见,作为Android的应用开发者你是否也想将这种动画做到你的应用中去呢?这一篇文章我们来看看如何自定义一个ImageView来实现让一张文字图片实现文字的遮罩闪 ...

  8. Android自定义组件系列【1】——自定义View及ViewGroup

    View类是ViewGroup的父类,ViewGroup具有View的所有特性,ViewGroup主要用来充当View的容器,将其中的View作为自己孩子,并对其进行管理,当然孩子也可以是ViewGr ...

  9. Android自定义组件系列【17】——教你如何高仿微信录音Toast

    一.Toast介绍 平时我们在Android开发中会经常用到一个叫Toast的东西,官方解释如下 A toast is a view containing a quick little message ...

随机推荐

  1. 最简单的TCP程序

    网络编程里面最简单的一个tcp程序,把一个文件从客户端上传到服务器端,上传成功后服务器端提示上传完成.代码不多,一个服务端和一个客户端. 服务端代码: import java.io.FileOutpu ...

  2. hdu 4825 xor sum(字典树+位运算)

    Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)Total S ...

  3. Linux cp 复制命令

    Linux 的cp命令 功能: 复制文件或目录说明: cp指令用于复制文件或目录,如同时指定两个以上的文件或目录,且最后的目的地是一个已经存在的目录,则它会把前面指定的所有文件或目录复制到此目录中.若 ...

  4. Mojom IDL and Bindings Generator

    Mojom IDL and Bindings Generator This document is a subset of the Mojo documentation. Contents Overv ...

  5. [转载]-分布式之redis复习精讲

    原创地址:https://www.cnblogs.com/rjzheng/p/9096228.html 看这篇文章前,我看的是另一个人博客上的文章.看到最后(评论这一块)很多人就指出这并非原创而是抄袭 ...

  6. PostgreSQL指定用户可访问的数据库pg_hba.conf

    进入指定目录: # cd /var/lib/pgsql/9.3/data/ 使用vi编辑pg_hba.conf文件 # vi pg_hba.conf 以上配置为所有IP及网关都允许访问,使用MD5认证 ...

  7. mac打包python3程序

    1. 下载安装py2app pip3 install py2app 2. 创建setup.py文件 py2applet --make-setup XXX.py 3. 发布应用 python3 setu ...

  8. Fans同学已死,终年24岁

    亲爱的同学们,朋友们,QQ好友. 告诉大家一个悲剧:Fans同学已死,终年24岁. 马甲变迁 正式告诉大家一个消息,我的ID"Fans同学"正在退出"历史舞台" ...

  9. ArcGIS api for javascript——以地理处理结果为条件查询地图

    这里发生什么任务呢?当第一次单击地图,单击的坐标被发送到一个Geoprocessor任务.该任务访问服务器上的通过ArcGIS Server 地理处理服务提供的可用的GIS模型.本例中模型计算驱动时间 ...

  10. 5.应用与模块(ng-app)

    转自:https://www.cnblogs.com/best/tag/Angular/ 自动载入启动一个AngularJS应用,声明了ng-app的元素会成为$rootScope的起点 每个HTML ...