一、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. NestedScrollView嵌套ListView可行性总结

    由于公司项目遗留代码仍然使用PullToRefreshListView(后文简称PTRLV),且存在复用,更换RecyclerView成本太大,同时又想使用CoordinatorLayout来实现一些 ...

  2. IHttpHandler的学习(0-2)

    这个IHttpHandler,要想到asp.net生命周期 ,想到哪个从你发起请求开始,这个请求通过HttpModule------>IHttpHandler的: 执行HttpModule的一系 ...

  3. jquery一些总结

    今天用jquery写一个js的效果,总结了几个方法. 获取jquery对象的css样式属性:css()方法,还可以更改其css样式:$(this).css('display') ;$(this).cs ...

  4. zookeeper启动闪退

    编辑zkServer.cmd在它的尾行加上 pause      就可以将闪退停住来观察闪退的原因. 遇到Exception in thread "main" java.lang. ...

  5. WebRTC Native APIs

    WebRTC Native APIs The WebRTC Native APIs implementation is based on W3C’s WebRTC 1.0: Real-time Com ...

  6. AWK行处理的用法实例

    第一节 awk的工作流程及基础用法 awk操作符会先检索文件的行信息,然后在行信息里找需要的内容. Awk的默认分割付是空格,awk '/模式/{print $1,$2}' file ##模式的位置可 ...

  7. 紫书 习题 10-9 UVa 294(正约数个数)

    一个数的正约数个数等于这个数的质因数分解后 每一项幂+1的积 因为每个质因数的幂可以为0, 1, 2--(注意可以为0) 所以就每个质因数配一个幂任意组合就可得一个正因数,根据乘法原理可得正约数个数. ...

  8. .NET 将 .config 文件嵌入到程序集

    原文:.NET 将 .config 文件嵌入到程序集 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Iron_Ye/article/details/ ...

  9. RvmTranslator7.0-IFC

    RvmTranslator7.0-IFC eryar@163.com RvmTranslator can translate the RVM file exported by AVEVA Plant( ...

  10. MKVToolNix v8.2

    32位版:http://pan.baidu.com/s/1i3s4gGd 64位版: http://pan.baidu.com/s/1gdvqbpp