提问人:JustAGuyWithALoaf 提问时间:5/11/2022 更新时间:5/17/2022 访问量:172
Xamarin Android:在重写的 OnDraw 方法中调用 Invalidate()
Xamarin Android: Calling Invalidate() inside overridden OnDraw method
问:
我正在创建一个自定义渲染器,它需要显示我在 Vulkan 引擎中渲染的任何内容。为此,我有一个 VulkanSurfaceView,它继承自 iOS 上的 MetalKit.MTKView,以及 Android 上的 Android.Views.SurfaceView 和 ISurfaceHolderCallback。
对于 iOS,我可以简单地这样做,只要视图在焦点上,它就会不断绘制一个新帧:
public class VulkanSurfaceView : MTKView, IVulkanAppHost
{
...
public override void Draw()
{
Renderer.Tick();
base.Draw();
}
}
但是,在 Android 上,我必须这样做,我从 OnDraw 方法中调用 Invalidate(),否则它只调用一次。我认为这段代码有点臭,我不确定这是否是“好”的方式。我的解决方案可以吗?如果没有,有人有更好的主意吗?
public class VulkanSurfaceView : SurfaceView, ISurfaceHolderCallback, IVulkanAppHost
{
...
protected override void OnDraw(Canvas? canvas)
{
Renderer.Tick();
base.OnDraw(canvas);
Invalidate();
}
}
答:
0赞
Bhargavi
5/12/2022
#1
您是否尝试在surfaceCreated方法中调用setWillNotDraw(false)? 参考链接
评论
0赞
JustAGuyWithALoaf
5/13/2022
是的,我已经这样做了,但这并不能使 Draw() 函数连续运行。可悲的是。
0赞
JustAGuyWithALoaf
5/17/2022
#2
谢谢@ToolmakerSteve。
我创建了一个计时器,如果请求了新帧(由我通过简单的布尔值),我将调用 Invalidate()。对于任何感兴趣的人,我这样做:
protected override void OnDraw(Canvas? canvas) // Just to show the updated OnDraw-method
{
Renderer.Tick();
base.OnDraw(canvas);
}
public void SurfaceCreated(ISurfaceHolder holder)
{
TickTimer = new System.Threading.Timer(state =>
{
AndroidApplication.SynchronizationContext.Send(_ => { if (NewFrameRequested) Invalidate(); }, state);
try { TickTimer.Change(0, Timeout.Infinite); } catch (ObjectDisposedException) { }
}, null, 0, Timeout.Infinite);
}
目前它非常简单,但它有效并且可能会增长。我最初使用这种方法的帧速率不佳的原因是误解了计时器的“dueTime”(请参阅 Timer 类),尽管我正在寻求帧速率。这实际上是帧之间的时间,现在看来很明显。
正如@Bhargavi提到的,如果在使视图无效时未调用 OnDraw,则需要设置“setWillNotDraw(false)”。
评论
Timer
Elapsed
mycontrol
mycontrol.Invalidate();
UpdateTick
Action
event EventHandler
() => mycontrol.Invalidate();
UpdateTick
public bool HasChanged;
if (HasChanged) { HasChanged = false; ...redraw code... }