SurfaceView使用方法简介-来自网络
2011-05-11 07:23
706 查看
本文来自
http://blog.csdn.net/hellogv/
,引用必须注明出处!
SurfaceView由于可以直接从内存或者DMA等硬件接口取得图像数据,因此是个非常重要的绘图容器,这次
我就用两篇文章来介绍SurfaceView的用法。网上介绍SurfaceView的用法有很多,写法也层出不同,例如继承SurfaceView类,
或者继承SurfaceHolder.Callback类等,这个可以根据功能实际需要自己选择,我这里就直接在普通的用户界面调用
SurfaceHolder的lockCanvas和unlockCanvasAndPost。
先来看看程序运行的截图:
截图1主要演示了直接把正弦波绘画在SurfaceView上
对比上面的左右两图,右图用.lockCanvas(null),而左图用.lockCanvas(new Rect(oldX, 0, oldX + length,
getWindowManager().getDefaultDisplay().getHeight())),
对比一下两个效果,由于左图是按指定Rect绘画,所以效率会比右图的全控件绘画高些,并且在清屏之后
(canvas.drawColor(Color.BLACK))不会留有上次绘画的残留。
接下来贴出main.xml的源码:
view plain
copy to clipboard
print
?
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
android:orientation
=
"vertical"
>
<
LinearLayout
android:id
=
"@+id/LinearLayout01"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
>
<
Button
android:id
=
"@+id/Button01"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"简单绘画"
>
</
Button
>
<
Button
android:id
=
"@+id/Button02"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"定时器绘画"
>
</
Button
>
</
LinearLayout
>
<
SurfaceView
android:id
=
"@+id/SurfaceView01"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
>
</
SurfaceView
>
</
LinearLayout
>
接下来贴出程序源码:
view plain
copy to clipboard
print
?
package
com.testSurfaceView;
import
java.util.Timer;
import
java.util.TimerTask;
import
android.app.Activity;
import
android.graphics.Canvas;
import
android.graphics.Color;
import
android.graphics.Paint;
import
android.graphics.Rect;
import
android.os.Bundle;
import
android.util.Log;
import
android.view.SurfaceHolder;
import
android.view.SurfaceView;
import
android.view.View;
import
android.widget.Button;
public
class
testSurfaceView
extends
Activity {
/** Called when the activity is first created. */
Button btnSimpleDraw, btnTimerDraw;
SurfaceView sfv;
SurfaceHolder sfh;
private
Timer mTimer;
private
MyTimerTask mTimerTask;
int
Y_axis[],
//保存正弦波的Y轴上的点
centerY,//中心线
oldX,oldY,//上一个XY点
currentX;//当前绘制到的X轴上的点
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnSimpleDraw = (Button) this
.findViewById(R.id.Button01);
btnTimerDraw = (Button) this
.findViewById(R.id.Button02);
btnSimpleDraw.setOnClickListener(new
ClickEvent());
btnTimerDraw.setOnClickListener(new
ClickEvent());
sfv = (SurfaceView) this
.findViewById(R.id.SurfaceView01);
sfh = sfv.getHolder();
//动态绘制正弦波的定时器
mTimer = new
Timer();
mTimerTask = new
MyTimerTask();
// 初始化y轴数据
centerY = (getWindowManager().getDefaultDisplay().getHeight() - sfv
.getTop()) / 2
;
Y_axis = new
int
[getWindowManager().getDefaultDisplay().getWidth()];
for
(
int
i =
1
; i < Y_axis.length; i++) {
// 计算正弦波
Y_axis[i - 1
] = centerY
- (int
) (
100
* Math.sin(i *
2
* Math.PI /
180
));
}
}
class
ClickEvent
implements
View.OnClickListener {
@Override
public
void
onClick(View v) {
if
(v == btnSimpleDraw) {
SimpleDraw(Y_axis.length-1
);
//直接绘制正弦波
} else
if
(v == btnTimerDraw) {
oldY = centerY;
mTimer.schedule(mTimerTask, 0
,
5
);
//动态绘制正弦波
}
}
}
class
MyTimerTask
extends
TimerTask {
@Override
public
void
run() {
SimpleDraw(currentX);
currentX++;//往前进
if
(currentX == Y_axis.length -
1
) {
//如果到了终点,则清屏重来
ClearDraw();
currentX = 0
;
oldY = centerY;
}
}
}
/*
* 绘制指定区域
*/
void
SimpleDraw(
int
length) {
if
(length ==
0
)
oldX = 0
;
Canvas canvas = sfh.lockCanvas(new
Rect(oldX,
0
, oldX + length,
getWindowManager().getDefaultDisplay().getHeight()));// 关键:获取画布
Log.i("Canvas:"
,
String.valueOf(oldX) + ","
+ String.valueOf(oldX + length));
Paint mPaint = new
Paint();
mPaint.setColor(Color.GREEN);// 画笔为绿色
mPaint.setStrokeWidth(2
);
// 设置画笔粗细
int
y;
for
(
int
i = oldX +
1
; i < length; i++) {
// 绘画正弦波
y = Y_axis[i - 1
];
canvas.drawLine(oldX, oldY, i, y, mPaint);
oldX = i;
oldY = y;
}
sfh.unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像
}
void
ClearDraw() {
Canvas canvas = sfh.lockCanvas(null
);
canvas.drawColor(Color.BLACK);// 清除画布
sfh.unlockCanvasAndPost(canvas);
}
}
注意一下 for (int i = oldX + 1; i < length; i++) {// 绘画正弦波
这句,在.lockCanvas()指定Rect内减少循环画线的次数,可以提高绘图效率。
上一篇
简
单介绍了SurfaceView的基本使用,这次就介绍SurfaceView与多线程的混搭。SurfaceView与多线程混搭,是为了防止动画闪烁
而实现的一种多线程应用。android的多线程用法与JAVA的多线程用法完全一样,本文不做多线程方面的介绍了。直接讲解SurfaceView与多
线程的混合使用,即开一条线程专门读取图片,另外一条线程专门绘图。
本文程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,一个专门绘图:
对
比一下,右边动画的帧速明显比左边的快,左右两者都没使用Thread.sleep()。为什么要开两个线程一个读一个画,而不去开两个线程像左边那样都
“边读边画”呢?因为SurfaceView每次绘图都会锁定Canvas,也就是说同一片区域这次没画完下次就不能画,因此要提高动画播放的效率,就得开一条线程专门画图,开另外一条线程做预处理的工作。
main.xml的源码:
view plain
copy to clipboard
print
?
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
android:orientation
=
"vertical"
>
<
LinearLayout
android:id
=
"@+id/LinearLayout01"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
>
<
Button
android:id
=
"@+id/Button01"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"单个独立线程"
>
</
Button
>
<
Button
android:id
=
"@+id/Button02"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"两个独立线程"
>
</
Button
>
</
LinearLayout
>
<
SurfaceView
android:id
=
"@+id/SurfaceView01"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
>
</
SurfaceView
>
</
LinearLayout
>
本文程序的源码:
view plain
copy to clipboard
print
?
package
com.testSurfaceView;
import
java.lang.reflect.Field;
import
java.util.ArrayList;
import
android.app.Activity;
import
android.graphics.Bitmap;
import
android.graphics.BitmapFactory;
import
android.graphics.Canvas;
import
android.graphics.Paint;
import
android.graphics.Rect;
import
android.os.Bundle;
import
android.util.Log;
import
android.view.SurfaceHolder;
import
android.view.SurfaceView;
import
android.view.View;
import
android.widget.Button;
public
class
testSurfaceView
extends
Activity {
/** Called when the activity is first created. */
Button btnSingleThread, btnDoubleThread;
SurfaceView sfv;
SurfaceHolder sfh;
ArrayList<Integer> imgList = new
ArrayList<Integer>();
int
imgWidth, imgHeight;
Bitmap bitmap;//独立线程读取,独立线程绘图
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnSingleThread = (Button) this
.findViewById(R.id.Button01);
btnDoubleThread = (Button) this
.findViewById(R.id.Button02);
btnSingleThread.setOnClickListener(new
ClickEvent());
btnDoubleThread.setOnClickListener(new
ClickEvent());
sfv = (SurfaceView) this
.findViewById(R.id.SurfaceView01);
sfh = sfv.getHolder();
sfh.addCallback(new
MyCallBack());
// 自动运行surfaceCreated以及surfaceChanged
}
class
ClickEvent
implements
View.OnClickListener {
@Override
public
void
onClick(View v) {
if
(v == btnSingleThread) {
new
Load_DrawImage(
0
,
0
).start();
//开一条线程读取并绘图
} else
if
(v == btnDoubleThread) {
new
LoadImage().start();
//开一条线程读取
new
DrawImage(imgWidth +
10
,
0
).start();
//开一条线程绘图
}
}
}
class
MyCallBack
implements
SurfaceHolder.Callback {
@Override
public
void
surfaceChanged(SurfaceHolder holder,
int
format,
int
width,
int
height) {
Log.i("Surface:"
,
"Change"
);
}
@Override
public
void
surfaceCreated(SurfaceHolder holder) {
Log.i("Surface:"
,
"Create"
);
// 用反射机制来获取资源中的图片ID和尺寸
Field[] fields = R.drawable.class
.getDeclaredFields();
for
(Field field : fields) {
if
(!
"icon"
.equals(field.getName()))
// 除了icon之外的图片
{
int
index =
0
;
try
{
index = field.getInt(R.drawable.class
);
} catch
(IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch
(IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 保存图片ID
imgList.add(index);
}
}
// 取得图像大小
Bitmap bmImg = BitmapFactory.decodeResource(getResources(),
imgList.get(0
));
imgWidth = bmImg.getWidth();
imgHeight = bmImg.getHeight();
}
@Override
public
void
surfaceDestroyed(SurfaceHolder holder) {
Log.i("Surface:"
,
"Destroy"
);
}
}
/*
* 读取并显示图片的线程
*/
class
Load_DrawImage
extends
Thread {
int
x, y;
int
imgIndex =
0
;
public
Load_DrawImage(
int
x,
int
y) {
this
.x = x;
this
.y = y;
}
public
void
run() {
while
(
true
) {
Canvas c = sfh.lockCanvas(new
Rect(
this
.x,
this
.y,
this
.x
+ imgWidth, this
.y + imgHeight));
Bitmap bmImg = BitmapFactory.decodeResource(getResources(),
imgList.get(imgIndex));
c.drawBitmap(bmImg, this
.x,
this
.y,
new
Paint());
imgIndex++;
if
(imgIndex == imgList.size())
imgIndex = 0
;
sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容
}
}
};
/*
* 只负责绘图的线程
*/
class
DrawImage
extends
Thread {
int
x, y;
public
DrawImage(
int
x,
int
y) {
this
.x = x;
this
.y = y;
}
public
void
run() {
while
(
true
) {
if
(bitmap !=
null
) {
//如果图像有效
Canvas c = sfh.lockCanvas(new
Rect(
this
.x,
this
.y,
this
.x
+ imgWidth, this
.y + imgHeight));
c.drawBitmap(bitmap, this
.x,
this
.y,
new
Paint());
sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容
}
}
}
};
/*
* 只负责读取图片的线程
*/
class
LoadImage
extends
Thread {
int
imgIndex =
0
;
public
void
run() {
while
(
true
) {
bitmap = BitmapFactory.decodeResource(getResources(),
imgList.get(imgIndex));
imgIndex++;
if
(imgIndex == imgList.size())
//如果到尽头则重新读取
imgIndex = 0
;
}
}
};
}
要创建一个新的SurfaceView,需要创建一个新的扩展了SurfaceView的类,并实现SurfaceHolder.Callback。
SurfaceHolder回调可以在底层的Surface被创建和销毁的时候通知View,并传递给它对SurfaceHolder对象的引用,其中包含了当前有效的Surface。
一个典型的Surface View设计模型包括一个由Thread所派生的类,它可以接收对当前的SurfaceHolder的引用,并独立地更新它。
下面的框架代码展示了使用Canvas所绘制的Surface View的实现。在Surface View控件中创建了一个新的由Thread派生的类,并且所有的UI更新都是在这个新类中处理的。
http://blog.csdn.net/hellogv/
,引用必须注明出处!
SurfaceView由于可以直接从内存或者DMA等硬件接口取得图像数据,因此是个非常重要的绘图容器,这次
我就用两篇文章来介绍SurfaceView的用法。网上介绍SurfaceView的用法有很多,写法也层出不同,例如继承SurfaceView类,
或者继承SurfaceHolder.Callback类等,这个可以根据功能实际需要自己选择,我这里就直接在普通的用户界面调用
SurfaceHolder的lockCanvas和unlockCanvasAndPost。
先来看看程序运行的截图:
截图1主要演示了直接把正弦波绘画在SurfaceView上
对比上面的左右两图,右图用.lockCanvas(null),而左图用.lockCanvas(new Rect(oldX, 0, oldX + length,
getWindowManager().getDefaultDisplay().getHeight())),
对比一下两个效果,由于左图是按指定Rect绘画,所以效率会比右图的全控件绘画高些,并且在清屏之后
(canvas.drawColor(Color.BLACK))不会留有上次绘画的残留。
接下来贴出main.xml的源码:
view plain
copy to clipboard
?
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
android:orientation
=
"vertical"
>
<
LinearLayout
android:id
=
"@+id/LinearLayout01"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
>
<
Button
android:id
=
"@+id/Button01"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"简单绘画"
>
</
Button
>
<
Button
android:id
=
"@+id/Button02"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"定时器绘画"
>
</
Button
>
</
LinearLayout
>
<
SurfaceView
android:id
=
"@+id/SurfaceView01"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
>
</
SurfaceView
>
</
LinearLayout
>
接下来贴出程序源码:
view plain
copy to clipboard
?
package
com.testSurfaceView;
import
java.util.Timer;
import
java.util.TimerTask;
import
android.app.Activity;
import
android.graphics.Canvas;
import
android.graphics.Color;
import
android.graphics.Paint;
import
android.graphics.Rect;
import
android.os.Bundle;
import
android.util.Log;
import
android.view.SurfaceHolder;
import
android.view.SurfaceView;
import
android.view.View;
import
android.widget.Button;
public
class
testSurfaceView
extends
Activity {
/** Called when the activity is first created. */
Button btnSimpleDraw, btnTimerDraw;
SurfaceView sfv;
SurfaceHolder sfh;
private
Timer mTimer;
private
MyTimerTask mTimerTask;
int
Y_axis[],
//保存正弦波的Y轴上的点
centerY,//中心线
oldX,oldY,//上一个XY点
currentX;//当前绘制到的X轴上的点
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnSimpleDraw = (Button) this
.findViewById(R.id.Button01);
btnTimerDraw = (Button) this
.findViewById(R.id.Button02);
btnSimpleDraw.setOnClickListener(new
ClickEvent());
btnTimerDraw.setOnClickListener(new
ClickEvent());
sfv = (SurfaceView) this
.findViewById(R.id.SurfaceView01);
sfh = sfv.getHolder();
//动态绘制正弦波的定时器
mTimer = new
Timer();
mTimerTask = new
MyTimerTask();
// 初始化y轴数据
centerY = (getWindowManager().getDefaultDisplay().getHeight() - sfv
.getTop()) / 2
;
Y_axis = new
int
[getWindowManager().getDefaultDisplay().getWidth()];
for
(
int
i =
1
; i < Y_axis.length; i++) {
// 计算正弦波
Y_axis[i - 1
] = centerY
- (int
) (
100
* Math.sin(i *
2
* Math.PI /
180
));
}
}
class
ClickEvent
implements
View.OnClickListener {
@Override
public
void
onClick(View v) {
if
(v == btnSimpleDraw) {
SimpleDraw(Y_axis.length-1
);
//直接绘制正弦波
} else
if
(v == btnTimerDraw) {
oldY = centerY;
mTimer.schedule(mTimerTask, 0
,
5
);
//动态绘制正弦波
}
}
}
class
MyTimerTask
extends
TimerTask {
@Override
public
void
run() {
SimpleDraw(currentX);
currentX++;//往前进
if
(currentX == Y_axis.length -
1
) {
//如果到了终点,则清屏重来
ClearDraw();
currentX = 0
;
oldY = centerY;
}
}
}
/*
* 绘制指定区域
*/
void
SimpleDraw(
int
length) {
if
(length ==
0
)
oldX = 0
;
Canvas canvas = sfh.lockCanvas(new
Rect(oldX,
0
, oldX + length,
getWindowManager().getDefaultDisplay().getHeight()));// 关键:获取画布
Log.i("Canvas:"
,
String.valueOf(oldX) + ","
+ String.valueOf(oldX + length));
Paint mPaint = new
Paint();
mPaint.setColor(Color.GREEN);// 画笔为绿色
mPaint.setStrokeWidth(2
);
// 设置画笔粗细
int
y;
for
(
int
i = oldX +
1
; i < length; i++) {
// 绘画正弦波
y = Y_axis[i - 1
];
canvas.drawLine(oldX, oldY, i, y, mPaint);
oldX = i;
oldY = y;
}
sfh.unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像
}
void
ClearDraw() {
Canvas canvas = sfh.lockCanvas(null
);
canvas.drawColor(Color.BLACK);// 清除画布
sfh.unlockCanvasAndPost(canvas);
}
}
注意一下 for (int i = oldX + 1; i < length; i++) {// 绘画正弦波
这句,在.lockCanvas()指定Rect内减少循环画线的次数,可以提高绘图效率。
上一篇
简
单介绍了SurfaceView的基本使用,这次就介绍SurfaceView与多线程的混搭。SurfaceView与多线程混搭,是为了防止动画闪烁
而实现的一种多线程应用。android的多线程用法与JAVA的多线程用法完全一样,本文不做多线程方面的介绍了。直接讲解SurfaceView与多
线程的混合使用,即开一条线程专门读取图片,另外一条线程专门绘图。
本文程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,一个专门绘图:
对
比一下,右边动画的帧速明显比左边的快,左右两者都没使用Thread.sleep()。为什么要开两个线程一个读一个画,而不去开两个线程像左边那样都
“边读边画”呢?因为SurfaceView每次绘图都会锁定Canvas,也就是说同一片区域这次没画完下次就不能画,因此要提高动画播放的效率,就得开一条线程专门画图,开另外一条线程做预处理的工作。
main.xml的源码:
view plain
copy to clipboard
?
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
android:orientation
=
"vertical"
>
<
LinearLayout
android:id
=
"@+id/LinearLayout01"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
>
<
Button
android:id
=
"@+id/Button01"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"单个独立线程"
>
</
Button
>
<
Button
android:id
=
"@+id/Button02"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"两个独立线程"
>
</
Button
>
</
LinearLayout
>
<
SurfaceView
android:id
=
"@+id/SurfaceView01"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
>
</
SurfaceView
>
</
LinearLayout
>
本文程序的源码:
view plain
copy to clipboard
?
package
com.testSurfaceView;
import
java.lang.reflect.Field;
import
java.util.ArrayList;
import
android.app.Activity;
import
android.graphics.Bitmap;
import
android.graphics.BitmapFactory;
import
android.graphics.Canvas;
import
android.graphics.Paint;
import
android.graphics.Rect;
import
android.os.Bundle;
import
android.util.Log;
import
android.view.SurfaceHolder;
import
android.view.SurfaceView;
import
android.view.View;
import
android.widget.Button;
public
class
testSurfaceView
extends
Activity {
/** Called when the activity is first created. */
Button btnSingleThread, btnDoubleThread;
SurfaceView sfv;
SurfaceHolder sfh;
ArrayList<Integer> imgList = new
ArrayList<Integer>();
int
imgWidth, imgHeight;
Bitmap bitmap;//独立线程读取,独立线程绘图
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnSingleThread = (Button) this
.findViewById(R.id.Button01);
btnDoubleThread = (Button) this
.findViewById(R.id.Button02);
btnSingleThread.setOnClickListener(new
ClickEvent());
btnDoubleThread.setOnClickListener(new
ClickEvent());
sfv = (SurfaceView) this
.findViewById(R.id.SurfaceView01);
sfh = sfv.getHolder();
sfh.addCallback(new
MyCallBack());
// 自动运行surfaceCreated以及surfaceChanged
}
class
ClickEvent
implements
View.OnClickListener {
@Override
public
void
onClick(View v) {
if
(v == btnSingleThread) {
new
Load_DrawImage(
0
,
0
).start();
//开一条线程读取并绘图
} else
if
(v == btnDoubleThread) {
new
LoadImage().start();
//开一条线程读取
new
DrawImage(imgWidth +
10
,
0
).start();
//开一条线程绘图
}
}
}
class
MyCallBack
implements
SurfaceHolder.Callback {
@Override
public
void
surfaceChanged(SurfaceHolder holder,
int
format,
int
width,
int
height) {
Log.i("Surface:"
,
"Change"
);
}
@Override
public
void
surfaceCreated(SurfaceHolder holder) {
Log.i("Surface:"
,
"Create"
);
// 用反射机制来获取资源中的图片ID和尺寸
Field[] fields = R.drawable.class
.getDeclaredFields();
for
(Field field : fields) {
if
(!
"icon"
.equals(field.getName()))
// 除了icon之外的图片
{
int
index =
0
;
try
{
index = field.getInt(R.drawable.class
);
} catch
(IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch
(IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 保存图片ID
imgList.add(index);
}
}
// 取得图像大小
Bitmap bmImg = BitmapFactory.decodeResource(getResources(),
imgList.get(0
));
imgWidth = bmImg.getWidth();
imgHeight = bmImg.getHeight();
}
@Override
public
void
surfaceDestroyed(SurfaceHolder holder) {
Log.i("Surface:"
,
"Destroy"
);
}
}
/*
* 读取并显示图片的线程
*/
class
Load_DrawImage
extends
Thread {
int
x, y;
int
imgIndex =
0
;
public
Load_DrawImage(
int
x,
int
y) {
this
.x = x;
this
.y = y;
}
public
void
run() {
while
(
true
) {
Canvas c = sfh.lockCanvas(new
Rect(
this
.x,
this
.y,
this
.x
+ imgWidth, this
.y + imgHeight));
Bitmap bmImg = BitmapFactory.decodeResource(getResources(),
imgList.get(imgIndex));
c.drawBitmap(bmImg, this
.x,
this
.y,
new
Paint());
imgIndex++;
if
(imgIndex == imgList.size())
imgIndex = 0
;
sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容
}
}
};
/*
* 只负责绘图的线程
*/
class
DrawImage
extends
Thread {
int
x, y;
public
DrawImage(
int
x,
int
y) {
this
.x = x;
this
.y = y;
}
public
void
run() {
while
(
true
) {
if
(bitmap !=
null
) {
//如果图像有效
Canvas c = sfh.lockCanvas(new
Rect(
this
.x,
this
.y,
this
.x
+ imgWidth, this
.y + imgHeight));
c.drawBitmap(bitmap, this
.x,
this
.y,
new
Paint());
sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容
}
}
}
};
/*
* 只负责读取图片的线程
*/
class
LoadImage
extends
Thread {
int
imgIndex =
0
;
public
void
run() {
while
(
true
) {
bitmap = BitmapFactory.decodeResource(getResources(),
imgList.get(imgIndex));
imgIndex++;
if
(imgIndex == imgList.size())
//如果到尽头则重新读取
imgIndex = 0
;
}
}
};
}
要创建一个新的SurfaceView,需要创建一个新的扩展了SurfaceView的类,并实现SurfaceHolder.Callback。
SurfaceHolder回调可以在底层的Surface被创建和销毁的时候通知View,并传递给它对SurfaceHolder对象的引用,其中包含了当前有效的Surface。
一个典型的Surface View设计模型包括一个由Thread所派生的类,它可以接收对当前的SurfaceHolder的引用,并独立地更新它。
下面的框架代码展示了使用Canvas所绘制的Surface View的实现。在Surface View控件中创建了一个新的由Thread派生的类,并且所有的UI更新都是在这个新类中处理的。
import android.content.Context; import android.graphics.Canvas; import android.view.SurfaceHolder; import android.view.SurfaceView; public class MySurfaceView extends SurfaceView implements SurfaceHolder. Callback { private SurfaceHolder holder; private MySurfaceViewThread mySurfaceViewThread; private boolean hasSurface; MySurfaceView(Context context) { super(context); init(); } private void init() { //创建一个新的SurfaceHolder, 并分配这个类作为它的回调(callback) holder = getHolder (); holder.addCallback(this); hasSurface = false ; } public void resume() { //创建和启动图像更新线程 if ( mySurfaceViewThread == null) { mySurfaceViewThread = new MySurfaceViewThread(); if ( hasSurface == true) mySurfaceViewThread.start(); } } public void pause() { // 杀死图像更新线程 if (mySurfaceViewThread != null) { mySurfaceViewThread.requestExitAndWait(); mySurfaceViewThread = null ; } } public void surfaceCreated(SurfaceHolder holder) { hasSurface = true ; if (mySurfaceViewThread != null) mySurfaceViewThread.start(); } public void surfaceDestroyed(SurfaceHolder holder) { hasSurface = false ; pause(); } public void surfaceChanged(SurfaceHolder holder,int format,int w,int h) { if (mySurfaceViewThread != null) mySurfaceViewThread.onWindowResize(w, h); } class MySurfaceViewThread extends Thread { private boolean done; MySurfaceViewThread() { super(); done = false ; } @Override public void run() { SurfaceHolder surfaceHolder = holder ; // 重复绘图循环,直到线程停止 while (!done) { // 锁定surface,并返回到要绘图的Canvas Canvas canvas = surfaceHolder .lockCanvas(); // 待实现:在Canvas上绘图 // 解锁Canvas,并渲染当前图像 surfaceHolder.unlockCanvasAndPost(canvas); } } public void requestExitAndWait() { // 把这个线程标记为完成,并合并到主程序线程 done = true ; try { join(); } catch (InterruptedException ex) { } } public void onWindowResize(int w, int h) { // 处理可用的屏幕尺寸的改变 } } }
相关文章推荐
- android学习笔记---44_在线视频播放器,网络视频解析器,SurfaceView 控件使用方法
- android学习笔记---44_在线视频播放器,网络视频解析器,SurfaceView 控件使用方法
- 播放视频android学习笔记---44_在线视频播放器,网络视频解析器,SurfaceView 控件使用方法
- 使用UIImageView展现来自网络的图片
- [Android]在游戏的SurfaceView中获取输入与使用EditText,Spinner等控件的方法
- Android---SurfaceView的使用方法
- 网络图片加载的第三方类:EGOImageView的使用方法及注意事项
- 使用UIImageView展现来自网络的图片
- Android SurfaceView使用方法
- 使用UIImageView展现来自网络的图片
- Android提高21篇之二:SurfaceView的基本使用方法
- Android提高21篇之二:SurfaceView的基本使用方法
- Android---SurfaceView的使用方法
- 使用UIImageView展现来自网络的图片
- 使用UIImageView展现来自网络的图片
- Android中ImageView使用网络图片资源的方法
- ViewPager+Fragment基本使用方法(转自网络)
- Android网络编程WebView使用方法
- android:使用SurfaceView游戏开发简单屏幕适配方法