灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:2973回复:0

Android 动态壁纸引擎试刀学习(初识安卓引擎)

楼主#
更多 发布于:2012-09-06 13:45

动态壁纸蛮好玩的,也没接触过,看官方有就拿了学习下,是小马第一次接触引擎Engine,激动兴奋...效果做出来了,就放博客里,记录笔记,吼吼,跟大家交流学习, 废话不多说了,先看效果,再看源码,之后小马会把安卓动态壁纸那个水波纹也写在博客里,供大家交流学习,今天的效果如下图所示,因为手机开机后就要加载图片,所以小马就直接从开机启动完成后讲了,看图...
未开锁时立方体形式一:

 
开锁时立方体形式一与二:




简单的绘制效果,因为立方体都是下面这些图(由三角形拼成的)拼的,所以此处贴下这个效果图,效果制作的代码我放在形式一注释里面了,大家可以试下的,就是这个效果,临时的:


工程结构如下图所示:


   因为形式一与形式二只是绘制点不一样,两个类都一样,防止篇幅过长(51有限制,超过80000字符就挂了,我已经超过了,这是第二边写了,所以形式二代码就不贴了),小马就直接贴形式一的代码与配置文件代码,详细的如有朋友要学习的话,下载下DEMO学习就是,小马基本的注释都加了,因为也在学习阶段,如有地方不足的,希望大家直接留言,批评指出,小马肯定感谢...
立方体形式一控制类代码:
  

1. package xiaoma.cube1;
2.
3. import Android.graphics.Canvas;
4. import Android.graphics.Paint;
5. import Android.os.Handler;
6. import Android.os.SystemClock;
7. import Android.service.wallpaper.WallpaperService;
8. import Android.view.MotionEvent;
9. import Android.view.SurfaceHolder;
10.
11. /**
12.  * @Title: CubeWallpaper1.java
13.  * @Package cube1
14.  * @Description: 初识Android动态壁纸引擎
15.  * @author XiaoMa
16.  */
17.
18. /*
19.  * 因为小马没接触过引擎,也无从下手学习,今天就拿官方的例子来试试刀了,
20.  * 吼吼,刚开始不知道,看了下代码,里面有讲到WallPaperService
21.  * 查询这个服务可以查到与之相关联的类与方法,如下面官方文档中讲的,大家
22.  * 英语不好也可以用工具看个大概,英语不好的朋友记得多用工具学习下,小马
23.  * 英语也不咋的....
24.  * A wallpaper service is responsible for showing a live wallpaper behind
25.  * applications that would like to sit on top of it. This service object itself
26.  * does very little -- its only purpose is to generate instances of
27.  * WallpaperService.Engine as needed. Implementing a wallpaper thus involves
28.  * subclassing from this, subclassing an Engine implementation, and implementing
29.  * onCreateEngine() to return a new instance of your engine
30.  * 上面讲的大体是:一个类必须是WallpaperService引擎类的子类,而且里面必须重写
31.  * onCreateEngine这个方法,要仔细看的话小马也看不懂英文,照着例子,看官方文档,
32.  * 多猜多用工具查就行了,小马英语烂的可以让你吐血...我能看懂,你肯定能看懂
33.  */
34. public class CubeWallpaper1 extends WallpaperService {
35.
36.     /*常用的都是这样的,用一个handler来动态的去刷新UI,对吧?猜的,看下面代码到底是不是*/
37.     private final Handler mHandler = new Handler();
38.
39.     /**
40.      * 这个方法与Activity里面的一样,当这个类的服务被第一次创建时
41.      * 调用,也就是说,这个方法只调用一次..
42.      */
43.     @Override
44.     public void onCreate() {
45.         super.onCreate();
46.     }
47.    
48.     /**
49.      * 与上面反的,销毁时调用,这个猜下,
50.      * 不懂了查文档
51.      */
52.     @Override
53.     public void onDestroy() {
54.         super.onDestroy();
55.     }
56.    
57.     /**
58.      * 这个方法在类注释中写明了
59.      * implementing onCreateEngine() to return a new instance of your engine
60.      * 必须实现这个方法来返回我们自己定义引擎的一个实例
61.      */
62.     @Override
63.     public Engine onCreateEngine() {
64.         return new CubeEngine();
65.     }
66.    
67.    
68.     /**
69.      *
70.     * @Title: CubeWallpaper1.java
71.     * @Package cube1
72.     * @Description: 自定义引擎类
73.     * @author XiaoMa
74.      */
75.     class CubeEngine extends Engine {
76.
77.         private final Paint mPaint = new Paint();
78.         private float mOffset;
79.         /*用户触摸位置*/
80.         private float mTouchX = -1;
81.         private float mTouchY = -1;
82.         private long mStartTime;
83.        
84.         /*屏幕中心坐标,记下,是中心不是原心(0,0)*/
85.         private float mCenterX;
86.         private float mCenterY;
87.
88.         private final Runnable mDrawCube = new Runnable() {
89.             public void run() {
90.                 drawFrame();
91.             }
92.         };
93.         private boolean mVisible;
94.
95.         CubeEngine() {
96.            
97.             /*下面这几行就为了在屏幕中画立方体的线条而做准备*/
98.             final Paint paint = mPaint;
99.             paint.setColor(0xffffffff);//画笔颜色
100.             paint.setAntiAlias(true);//抗锯齿
101.             paint.setStrokeWidth(2);//线条粗细,猜的,不知道对不对
102.             paint.setStrokeCap(Paint.Cap.ROUND);
103.             paint.setStyle(Paint.Style.STROKE);
104.             //系统启动完之后,开始绘制壁纸的时间,这个时间里面包含有系统睡眠时间
105.             mStartTime = SystemClock.elapsedRealtime();
106.         }
107.        
108.         /**
109.          * 大家发现这个onCreate与Activity的方法有什么不同了吧?
110.          * 老规矩的,还是在初始化壁纸引擎的时候调用这个方法,并设置触
111.          * 屏事件为可用
112.          */
113.         @Override
114.         public void onCreate(SurfaceHolder surfaceHolder) {
115.             super.onCreate(surfaceHolder);
116.             setTouchEventsEnabled(true);
117.         }
118.
119.         @Override
120.         public void onDestroy() {
121.             super.onDestroy();
122.             mHandler.removeCallbacks(mDrawCube);
123.         }
124.        
125.         /**
126.          * 系统壁纸状态改变时会调用这个方法,如:
127.          * 壁纸由隐藏转换为显示状态时会调用这个方法
128.          */
129.         @Override
130.         public void onVisibilityChanged(boolean visible) {
131.             mVisible = visible;
132.             /*下面这个判断好玩,就是说,如果屏幕壁纸状态转为显式时重新绘制壁纸,否则黑屏幕,隐藏就可以*/
133.             if (visible) {
134.                 drawFrame();
135.             } else {
136.                 mHandler.removeCallbacks(mDrawCube);
137.             }
138.         }
139.
140.         @Override
141.         public void onSurfaceChanged(SurfaceHolder holder, int format,
142.                 int width, int height) {
143.             super.onSurfaceChanged(holder, format, width, height);
144.             //下面是来保存屏幕显示立方体的,也就是你能看到的正面图的中心位置
145.             mCenterX = width / 2.0f;
146.             mCenterY = height / 2.0f;
147.             drawFrame();
148.         }
149.        
150.         /**
151.          * 下面两个方法是为了方便调用SurfaceHolder交互来重写的
152.          */
153.         @Override
154.         public void onSurfaceCreated(SurfaceHolder holder) {
155.             super.onSurfaceCreated(holder);
156.         }
157.
158.         @Override
159.         public void onSurfaceDestroyed(SurfaceHolder holder) {
160.             super.onSurfaceDestroyed(holder);
161.             mVisible = false;
162.             mHandler.removeCallbacks(mDrawCube);
163.         }
164.        
165.         /**
166.          * 当手动壁纸时根据偏移量重绘壁纸
167.          */
168.         @Override
169.         public void onOffsetsChanged(float xOffset, float yOffset, float xStep,
170.                 float yStep, int xPixels, int yPixels) {
171.             mOffset = xOffset;
172.             drawFrame();
173.         }
174.
175.         /*
176.          * 在这个地方保存触摸的位置,我们会在绘制壁纸的时候使用触摸值
177.          */
178.         @Override
179.         public void onTouchEvent(MotionEvent event) {
180.             if (event.getAction() == MotionEvent.ACTION_MOVE) {
181.                 mTouchX = event.getX();
182.                 mTouchY = event.getY();
183.             } else {
184.                 mTouchX = -1;
185.                 mTouchY = -1;
186.             }
187.             super.onTouchEvent(event);
188.         }
189.
190.         /*
191.          * 绘制立方体方法实现
192.          */
193.         void drawFrame() {
194.             final SurfaceHolder holder = getSurfaceHolder();
195.
196.             Canvas c = null;
197.             try {
198.                 c = holder.lockCanvas();
199.                 if (c != null) {
200.                     drawCube(c);
201.                     drawTouchPoint(c);
202.                 }
203.             } finally {
204.                 if (c != null)
205.                     holder.unlockCanvasAndPost(c);
206.             }
207.
208.             // 在指定时间里重绘制,这个地方大家可以看效果图,如果你拖动过快的话,立方体
209.             //每个顶点之间会有一个短暂的未连接延迟,就是在这个地方使用了延迟来绘制的
210.             mHandler.removeCallbacks(mDrawCube);
211.             if (mVisible) {
212.                 mHandler.postDelayed(mDrawCube, 1000 / 25);
213.             }
214.         }
215.
216.         /*
217.          *  这个地方是以立方体某个顶点为起始端,绘制三条线
218.          *  一堆数字,看着好晕  
219.          *  在这小马顺便贴在这个DEMO里面用到的基本的绘制,如下:
220.          *  graphics.Canvas有四种画矩形的方法。
221.             canvas.drawRect(new RectF(10, 10, 300, 100), paint);
222.             canvas.drawRect(10, 150, 300, 200, paint);
223.             canvas.drawRect(new Rect(10, 250, 300, 300), paint);
224.             第四种:画圆角的矩形
225.             canvas.drawRoundRect(new RectF(10, 350, 300, 450), 10, 10, paint);
226.             第二个和第三个参数为圆角的宽高。
227.             有兴趣的朋友可以改下下面这些东西
228.          */
229.         void drawCube(Canvas c) {
230.             c.save();
231.             c.translate(mCenterX, mCenterY);
232.             c.drawColor(0xff000000);
233.             drawLine(c, -400, -400, -400, 400, -400, -400);
234.             drawLine(c, 400, -400, -400, 400, 400, -400);
235.             drawLine(c, 400, 400, -400, -400, 400, -400);
236.             drawLine(c, -400, 400, -400, -400, -400, -400);
237.
238.             drawLine(c, -400, -400, 400, 400, -400, 400);
239.             drawLine(c, 400, -400, 400, 400, 400, 400);
240.             drawLine(c, 400, 400, 400, -400, 400, 400);
241.             drawLine(c, -400, 400, 400, -400, -400, 400);
242.
243.             drawLine(c, -400, -400, 400, -400, -400, -400);
244.             drawLine(c, 400, -400, 400, 400, -400, -400);
245.             drawLine(c, 400, 400, 400, 400, 400, -400);
246.             drawLine(c, -400, 400, 400, -400, 400, -400);
247.             c.restore();
248.         }
249.
250.         /*
251.          * 在屏幕中绘制三维空间的线
252.          */
253.         void drawLine(Canvas c, int x1, int y1, int z1, int x2, int y2, int z2) {
254.             /*
255.              *因为大家都知道,壁纸是手机启动完成之后就已经开始绘制的,一般取时间什么的
256.              *我们都用Timer System.currentTimeMillis() Calendar来取
257.              *这个地方取系统级启动时间等的,记住这个类,SystemClock,方法自己查
258.              */
259.             long now = SystemClock.elapsedRealtime();
260.             /*取得三维坐标轴的旋转值*/
261.             float xrot = ((float) (now - mStartTime)) / 1000;
262.             float yrot = (0.5f - mOffset) * 2.0f;
263.             float zrot = 0;
264.
265.
266.             // rotation around X-axis  ???
267.             float newy1 = (float) (Math.sin(xrot) * z1 + Math.cos(xrot) * y1);
268.             float newy2 = (float) (Math.sin(xrot) * z2 + Math.cos(xrot) * y2);
269.             float newz1 = (float) (Math.cos(xrot) * z1 - Math.sin(xrot) * y1);
270.             float newz2 = (float) (Math.cos(xrot) * z2 - Math.sin(xrot) * y2);
271.
272.             // rotation around Y-axis  ???
273.             float newx1 = (float) (Math.sin(yrot) * newz1 + Math.cos(yrot) * x1);
274.             float newx2 = (float) (Math.sin(yrot) * newz2 + Math.cos(yrot) * x2);
275.             newz1 = (float) (Math.cos(yrot) * newz1 - Math.sin(yrot) * x1);
276.             newz2 = (float) (Math.cos(yrot) * newz2 - Math.sin(yrot) * x2);
277.
278.             // 3D-to-2D projection  ???
279.             float startX = newx1 / (4 - newz1 / 400);
280.             float startY = newy1 / (4 - newz1 / 400);
281.             float stopX = newx2 / (4 - newz2 / 400);
282.             float stopY = newy2 / (4 - newz2 / 400);
283.
284.             c.drawLine(startX, startY, stopX, stopY, mPaint);
285.         }
286.
287.         /*
288.          * 按位屏幕手动时绘制一个白色的圈
289.          */
290.         void drawTouchPoint(Canvas c) {
291.             if (mTouchX >= 0 ;; mTouchY >= 0) {
292.                 c.drawCircle(mTouchX, mTouchY, 80, mPaint);
293.             }
294.         }
295.
296.     }
297. }
配置文件代码如下:
1. <?xml version="1.0" encoding="utf-8"?>
2. <manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
3.     package="xiaoma.cube1"
4.     Android:versionCode="1"
5.     Android:versionName="1.0" >
6.
7.     <uses-sdk Android:minSdkVersion="7" />
8.     <!-- 小马试的,如果下面uses-feature两名句话不加的话会报
9.         ClassNotFoundException 异常的哦,所以大家务必加上
10.      -->
11.     <uses-feature Android:name="Android.software.live_wallpaper" />
12.     <uses-feature Android:name="Android.software.live_wallpaper" />
13.
14.     <application
15.         Android:label="@string/wallpapers"
16.         Android:icon="@drawable/ic_launcher">
17.        
18.         <!-- 立方体形式一 -->
19.         <service
20.             Android:label="@string/wallpaper_cube1"
21.             Android:name=".CubeWallpaper1"
22.             Android:permission="Android.permission.BIND_WALLPAPER">
23.             <intent-filter>
24.                 <action Android:name="Android.service.wallpaper.WallpaperService" />
25.             </intent-filter>
26.             <meta-data Android:name="Android.service.wallpaper" Android:resource="@xml/cube1" />
27.         </service>
28.
29.         <!-- 立方体形式二 -->
30.         <service
31.             Android:label="@string/wallpaper_cube2"
32.             Android:name=".CubeWallpaper2"
33.             Android:permission="Android.permission.BIND_WALLPAPER">
34.             <intent-filter>
35.                 <action Android:name="Android.service.wallpaper.WallpaperService" />
36.             </intent-filter>
37.             <meta-data Android:name="Android.service.wallpaper" Android:resource="@xml/cube2" />
38.         </service>
39.         <!-- 立方体形式二偏好控制类 -->
40.         <activity
41.             Android:label="@string/cube2_settings"
42.             Android:name=".CubeWallpaper2Settings"
43.             Android:theme="@Androidtyle/Theme.Light.WallpaperSettings"
44.             Android:exported="true">
45.         </activity>
46.
47.     </application>
48.
49. </manifest>
      最后,看不懂小马注释的,可以自己修改下里面的点试下,看是什么效果就知道了,呵呵,小马也是第一次接触引擎这个东西,大牛多指点下,期待...因为不知道从哪开始学这些东西,就学习了下官方的,可以的话,神人多多赐教,小马一定感激的...谢谢,小DEMO源码我放附件里了,跟小马一样的菜菜可以下下来学习学习,嘿嘿,,加油加油


喜欢0 评分0
游客

返回顶部