Android自定义View的onDraw方法无法更新Canvas内Bitmap位置如何解决
问题根因
你遇到的核心错误有两个:
- 你注释了触发View重绘的
invalidate()方法,反而主动调用了customView.draw(canvas)方法。Android View的绘制流程由系统统一调度,你手动传入的canvas并非系统最终用来渲染到屏幕的目标画布,所以你用新x值绘制的内容不会显示到用户可见的界面上,这也是为什么你Log里能看到x值更新,但界面上Bitmap位置没变的原因。 - 你没有主动通知系统你的View内容发生了变化,系统不会主动重新调用
onDraw方法刷新界面,用户看到的永远是第一次系统调度绘制时的结果。
修复方案
- 删掉Activity中所有
customView.draw(canvas)的调用,打开invalidate()的注释,修改完x值后直接调用invalidate()通知系统重绘即可。 - 优化自定义View的代码,避免在
onDraw中重复创建Paint对象,调整super.onDraw的调用顺序到方法开头(避免自定义绘制内容被父类逻辑覆盖)。
修复后的Activity代码
if (callback2 > 0 && callback2 <= 0.1) { customView.x = 468; customView.invalidate(); } else if (callback2 < 0) { customView.x = 650; customView.invalidate(); } else if (callback2 > 0.1) { customView.x = 270; customView.invalidate(); }
注意:如果你的上述代码是在非UI线程中执行,需要把
invalidate()替换为postInvalidate(),避免线程报错。
修复后的自定义View代码
public class TheCustomView extends View { Bitmap scaledRollerBottom; Bitmap backgroundMask; Bitmap rollerBottom; Bitmap overlayBitmap; float x; // 全局共用Paint,避免onDraw中重复创建造成内存抖动 private Paint mPaint; public TheCustomView(Context context) { super(context); initPaint(); } public TheCustomView(Context context, AttributeSet attr) { super(context, attr); initPaint(); BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_8888; backgroundMask = BitmapFactory.decodeResource(getResources(), R.drawable.background_new, options); rollerBottom = BitmapFactory.decodeResource(getResources(), R.drawable.roller_bottom, options); Bitmap scaledBackgroundMask = Bitmap.createScaledBitmap(backgroundMask, 1000, 1000, true); scaledRollerBottom = Bitmap.createScaledBitmap(rollerBottom, 120, 31, false); } private void initPaint() { mPaint = new Paint(); } @Override protected void onDraw(Canvas canvas) { // 先调用父类绘制逻辑,再执行自定义绘制 super.onDraw(canvas); Log.v("X ", "is " + x); canvas.drawBitmap(scaledRollerBottom, x, 915f, mPaint); } }
内容的提问来源于stack exchange,提问作者Elvin Mammadov
相关产品推荐
相关产品推荐

