一、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. Swift学习笔记(2):错误处理

    目录: Error do-catch 断言 Error 在 Swift 中,错误用符合 Error 协议的类型的值来表示.这个空协议表明该类型可以用于错误处理异常. Swift 的枚举类型尤为适合构建 ...

  2. FragmentPagerAdapter和FragmentStatePagerAdapter的区别

    FragmentPagerAdapter 1:简单的介绍: 该类内的每一个生成的 Fragment 都将保存在内存之中,因此适用于那些相对静态的页,数量也比较少的那种:如果需要处理有很多页,并且数据动 ...

  3. mac终端(terminal)里的快捷键

    Command + K 清屏 Command + T 新建标签 Command +W 关闭当前标签页 Command + S 保存终端输出 Command + D 垂直分隔当前标签页 Command ...

  4. Chrome发布73 beta版:增强Linux用户体验

    Google开发者周五推动Chrome 73进入他们的测试频道,因为他们准备在3月12日左右推出这款网页浏览器更新,以便稳定推出.除非另有说明,否则下面描述的更改适用于Android,Chrome O ...

  5. django orm 时间处理

    说明  datetime 类型赋值: 数据库设置时区为:utc 系统设置时区为:'Asia/Shanghai' 1.赋值为:‘2019-04-24 15:00:00’      数据库的结果为   ‘ ...

  6. vue+element的表格分页和前端搜索

    1.前端后台管理会存在很多表格,表格数据过多就需要分页;2.前端交互每次搜索如果都请求服务器会加大服务器的压力,所以在数据量不是很大的情况下可以一次性将数据返回,前端做检索3.下面贴上一个demo & ...

  7. 浴谷 P1768 天路

    P1768 天路 题目描述 “那是一条神奇的天路诶~,把第一个神犇送上天堂~”,XDM先生唱着这首“亲切”的歌曲,一道猥琐题目的灵感在脑中出现了. 和C_SUNSHINE大神商量后,这道猥琐的题目终于 ...

  8. 三 概要模式 2) MR倒排索引、性能分析、搜索干扰词。

    二  倒排索引     倒排索引(英语:Inverted index),也常被称为反向索引.置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射. ...

  9. [B cannot be cast to java.lang.String

    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) sun.reflect.NativeMethodAccessorImpl.inv ...

  10. 18.angularJS服务

    转自:https://www.cnblogs.com/best/tag/Angular/ 服务 AngularJS功能最基本的组件之一是服务(Service).服务为你的应用提供基于任务的功能.服务可 ...