动态壁纸中如何实现多Canvas绘制(一静一动)?
嘿,其实你根本不需要多个Canvas就能搞定这个需求!动态壁纸的绘制逻辑里,单Canvas分层绘制就可以完美实现你的需求:先绘制背景Bitmap,再在手指位置绘制移动对象,每次onDraw时重新绘制整个画面,自然就能呈现出对象跟随手指移动的效果。
实现动态壁纸的正确思路(无需多Canvas)
1. 基础框架:创建WallpaperService和Engine子类
动态壁纸的核心是继承WallpaperService,并实现内部的Engine类,所有绘制、触摸逻辑都在Engine里处理。
2. 加载资源并初始化坐标
在Engine的初始化方法里加载背景和移动对象的Bitmap,同时初始化触摸坐标(比如默认在屏幕中心),注意要做内存优化,避免大图导致的OOM:
private Bitmap backgroundBitmap; private Bitmap movingObjectBitmap; private float touchX, touchY; @Override public void onCreate(SurfaceHolder surfaceHolder) { super.onCreate(surfaceHolder); // 允许壁纸接收触摸事件 setTouchEventsEnabled(true); // 加载背景图(以资源文件为例) backgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg_wallpaper); // 加载跟随手指的对象图 movingObjectBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.follow_object); // 初始化默认坐标为屏幕中心 DisplayMetrics metrics = getResources().getDisplayMetrics(); touchX = metrics.widthPixels / 2f; touchY = metrics.heightPixels / 2f; }
3. 处理触摸事件,实时更新坐标
重写onTouchEvent方法,记录手指的实时位置,然后触发重绘:
@Override public void onTouchEvent(MotionEvent event) { super.onTouchEvent(event); // 更新触摸坐标 touchX = event.getX(); touchY = event.getY(); // 触发画布重绘 SurfaceHolder holder = getSurfaceHolder(); Canvas canvas = holder.lockCanvas(); if (canvas != null) { onDraw(canvas); holder.unlockCanvasAndPost(canvas); } }
4. 核心绘制:单Canvas分层渲染
在onDraw方法里,按顺序绘制背景和移动对象——先画背景覆盖整个画布,再在触摸坐标处绘制对象,这样每次重绘都会覆盖之前的画面,视觉上就呈现出对象跟随移动的效果:
@Override public void onDraw(Canvas canvas) { super.onDraw(canvas); if (backgroundBitmap == null) return; // 1. 绘制背景,铺满整个屏幕 canvas.drawBitmap(backgroundBitmap, 0, 0, null); // 2. 绘制跟随对象(调整坐标让对象中心对准手指) float objectOffsetX = movingObjectBitmap.getWidth() / 2f; float objectOffsetY = movingObjectBitmap.getHeight() / 2f; canvas.drawBitmap(movingObjectBitmap, touchX - objectOffsetX, touchY - objectOffsetY, null); // 如果需要更平滑的过渡,可以添加延迟重绘,维持60fps的刷新 postDelayed(() -> { SurfaceHolder holder = getSurfaceHolder(); Canvas refreshCanvas = holder.lockCanvas(); if (refreshCanvas != null) { onDraw(refreshCanvas); holder.unlockCanvasAndPost(refreshCanvas); } }, 16); }
收尾:回收资源避免内存泄漏
记得在Engine销毁时回收Bitmap资源:
@Override public void onDestroy() { super.onDestroy(); if (backgroundBitmap != null && !backgroundBitmap.isRecycled()) { backgroundBitmap.recycle(); } if (movingObjectBitmap != null && !movingObjectBitmap.isRecycled()) { movingObjectBitmap.recycle(); } }
关键说明
为什么不用多Canvas?因为动态壁纸的SurfaceHolder每次提供的Canvas是用于整个画面绘制的,我们只需要通过绘制顺序实现分层:背景先画(覆盖旧画面),对象后画(叠加在背景上),这样就模拟出了“两层”的视觉效果,完全不需要多个Canvas。
内容的提问来源于stack exchange,提问作者kazmer1998
相关产品推荐
相关产品推荐

