Xamarin.Android中Invalidate()未触发OnDraw()问题求助
解决触摸按下时重绘不立即触发的问题
看起来你遇到的问题是触摸事件处理中,Invalidate()的重绘请求被延迟到触摸抬起后才执行,导致按下状态的图片始终看不到。这是因为Android的UI线程消息循环机制:触摸事件的处理是在UI线程执行的,直接调用Invalidate()只是标记视图需要重绘,实际的OnDraw()会等待当前触摸事件处理完成后才会执行。如果抬起事件紧接着触发并也调用了重绘,就会覆盖按下状态的绘制请求。
下面是具体的解决方案和优化代码:
1. 核心修复:确保按下事件的重绘优先执行
修改你的触摸事件处理逻辑,用Post()将重绘请求加入UI消息队列,让它在当前触摸事件处理过程中就被调度执行,同时要正确标记事件已处理:
private void MyView_Touch(object sender, TouchEventArgs e) { var myView = sender as View; if (myView == null) return; switch (e.Event.Action) { case MotionEventActions.Down: // 设置按下状态的图片 SetSelectedPart(Resource.Drawable.Green); // 使用Post将重绘请求放到消息队列,确保当前事件流程中触发OnDraw myView.Post(() => myView.Invalidate()); // 返回true,告知系统当前View要处理后续触摸事件 e.Handled = true; break; case MotionEventActions.Up: // 设置抬起状态的图片 SetSelectedPart(Resource.Drawable.YourDefaultDrawable); myView.Invalidate(); e.Handled = true; break; case MotionEventActions.Cancel: // 触摸被中断时也要恢复默认状态 SetSelectedPart(Resource.Drawable.YourDefaultDrawable); myView.Invalidate(); e.Handled = true; break; default: e.Handled = false; break; } }
2. 确保SetSelectedPart和OnDraw逻辑正确
检查你的SetSelectedPart方法是否正确初始化了Drawable,并且OnDraw中正确绘制它:
private Drawable _currentDrawable; private void SetSelectedPart(int drawableResId) { // 获取Drawable并设置正确的绘制边界 _currentDrawable = Resources.GetDrawable(drawableResId); _currentDrawable.SetBounds(0, 0, Width, Height); } protected override void OnDraw(Canvas canvas) { base.OnDraw(canvas); // 确保Drawable不为空时才绘制 if (_currentDrawable != null) { _currentDrawable.Draw(canvas); } }
为什么这样有效?
myView.Post(() => myView.Invalidate()):将重绘请求异步投递到UI线程的消息队列,这样它会在当前触摸事件处理的间隙被执行,而不是等到整个触摸事件序列(Down→Up)处理完。e.Handled = true:在Down事件中返回true,确保当前View能接收后续的Up/Cancel事件,避免系统将触摸事件传递给父容器,保证状态切换的完整性。- 处理
MotionEventActions.Cancel:当触摸被系统中断(比如滑动到其他控件)时,也能恢复默认状态,避免图片停留在按下状态。
内容的提问来源于stack exchange,提问作者Praddy
相关产品推荐
相关产品推荐

