橘子味的心
标题:10.5 使用SurfaceView绘制动态图像

实例 SurfaceViewDrawDemo 绘制的是一幅静态图像,而使用 SurfaceView 可以绘制动态图像。

绘制动态图像的过程应该在一个单独的线程中完成,而不应该在主线程中进行。实例 SurfaceViewDynDrawDemo 演示了使用 SurfaceView 组件绘制动态图像的过程。

该实例修改自 Android SDK 提供的实例,绘制的是类似于 Windows 中的变幻线屏保的效果,运行效果如图 1 所示。
实例SurfaceViewDynDrawDemo的运行效果
图 1  实例 SurfaceViewDynDrawDemo 的运行效果

实例 SurfaceViewDynDrawDemo 的布局文件 main.xml 内容如下:
  1. <?xml version="1.0" encoding="utf-8"?>
  2.  
  3. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. android:orientation="vertical">
  7.  
  8. <TextView
  9. android:layout_width="fill_parent"
  10. android:layout_height="wrap_content"
  11. android:text="@string/hello" />
  12.  
  13. <SurfaceView
  14. android:id="@+id/surfaceViewl"
  15. android:layout_width="fill_parent"
  16. android:layout_height="fill_parent" />
  17. </LinearLayout>
实例 SurfaceViewDynDrawDemo 的主 Activity 为 SurfaceViewDynDrawDemoActivity,其代码如下:
  1. import android.app.Activity;
  2. import android.graphics.Canvas;
  3. import android.graphics.Paint;
  4. import android.os.Bundle;
  5. import android.util.Log;
  6. import android.view.SurfaceHolder;
  7. import android.view.SurfaceView;
  8.  
  9. public class SurfaceViewDynDrawDemoActivity extends Activity {
  10. private SurfaceView mySurfaceView;
  11. private DrawingThread mDrawingThread;
  12. SurfaceHolder surfaceHolder;
  13.  
  14. /**
  15. * Called when the activity is first created.
  16. */
  17. @Override
  18. public void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.main);
  21. mySurfaceView = (SurfaceView) findViewById(R.id.surfaceViewl);
  22. surfaceHolder = mySurfaceView.getHolder();
  23. surfaceHolder.addCallback(new SurfaceHolder.Callback() {
  24.  
  25. @Override
  26. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  27. // TODO Auto-generated method stub
  28. }
  29.  
  30. @Override
  31. public void surfaceCreated(SurfaceHolder holder) {
  32. // TODO Auto-generated method stub
  33. mDrawingThread = new DrawingThread();
  34. mDrawingThread.mSurface = surfaceHolder;
  35. mDrawingThread.start();
  36. }
  37.  
  38. @Override
  39. public void surfaceDestroyed(SurfaceHolder holder) {
  40. // TODO Auto-generated method stub
  41. mDrawingThread.mQuit = true;
  42. }
  43. });
  44. }
  45.  
  46. static final class MovingPoint {
  47. float x, y, dx, dy;
  48.  
  49. void init(int width, int height, float minStep) {
  50. x = (float) ((width - 1) * Math.random());
  51. y = (float) ((height - 1) * Math.random());
  52. dx = (float) (Math.random() * minStep * 2) + 1;
  53. dy = (float) (Math.random() * minStep * 2) + 1;
  54. }
  55.  
  56. float adjDelta(float cur, float minStep, float maxStep) {
  57. cur += (Math.random() * minStep) - (minStep / 2);
  58. if (cur < 0 && cur > -minStep) cur = -minStep;
  59. if (cur >= 0 && cur < minStep) cur = minStep;
  60. if (cur > maxStep) cur = maxStep;
  61. if (cur < -maxStep) cur = -maxStep;
  62. return cur;
  63. }
  64.  
  65. void step(int width, int height, float minStep, float maxStep) {
  66. x += dx;
  67. if (x <= 0 || x >= (width - 1)) {
  68. if (x <= 0) x = 0;
  69. else if (x >= (width - 1)) x = width - 1;
  70. dx = adjDelta(-dx, minStep, maxStep);
  71. }
  72. y += dy;
  73. if (y <= 0 || y >= (height - 1)) {
  74. if (y <= 0) y = 0;
  75. else if (y >= (height - 1)) y = height - 1;
  76. dy = adjDelta(-dy, minStep, maxStep);
  77. }
  78. }
  79. }
  80.  
  81. class DrawingThread extends Thread {
  82. // These are protected by the Thread's lock
  83. SurfaceHolder mSurface;
  84. boolean mRunning;
  85. boolean mActive;
  86. boolean mQuit;
  87. // Internal state
  88. int mLineWidth;
  89. float mMinStep;
  90. float mMaxStep;
  91.  
  92. boolean mInitialized = false;
  93. final MovingPoint mPoint1 = new MovingPoint();
  94. final MovingPoint mPoint2 = new MovingPoint();
  95.  
  96. static final int NUM_OLD = 100;
  97. int mNum0ld = 0;
  98. final float[] m0ld = new float[NUM_OLD * 4];
  99. final int[] m01dColor = new int[NUM_OLD];
  100. int mBrightLine = 0;
  101.  
  102. // X is red, Y is blue
  103. final MovingPoint mColor = new MovingPoint();
  104.  
  105. final Paint mBackground = new Paint();
  106. final Paint mForeground = new Paint();
  107.  
  108. int makeGreen(int index) {
  109. int dist = Math.abs(mBrightLine - index);
  110. if (dist > 10) return 0;
  111. return (255 - (dist * (255 / 10))) << 8;
  112. }
  113.  
  114. @Override
  115. public void run() {
  116. mLineWidth = (int