【问题标题】:The Draw method of IDrawable is not always called during a call to Invalidate在调用 Invalidate 期间并不总是调用 IDrawable 的 Draw 方法
【发布时间】:2022-11-10 19:33:17
【问题描述】:

我尝试为 GraphicsView 的内容设置动画,

private void OnLoaded(object sender, EventArgs e)
{
    var animation = new Animation(v => AngleSpan = v, 0, 360D, Easing.CubicInOut);
    animation.Commit(this, "AngleAnimation", 8, 1500);
}

但是动画很生涩(当两个图像之间有 8ms 的延迟时,20ips 应该让我更接近 120ips)。

通过在调用 GraphicsView 的 Invalidate 之前和在我的 IDrawable 的 Draw 方法中添加一个 Debug.WriteLine,我意识到 Draw 方法平均只有 3 次调用一次。

Invalidate
Invalidate
Draw
Invalidate
Invalidate
Draw
Invalidate
Invalidate
Invalidate
Draw
Invalidate
Invalidate
Invalidate
Draw
[...]

对 Invalidate 的调用不应该确保始终调用 Draw 方法吗?

如果不是这样,我必须有什么选择才能获得流畅的动画?

编辑

我正在添加一些与 cmets 中提出的问题相关的上下文和说明:

动画通过 AngleSpan 属性的设置器触发对“Invalidate”的调用。

public class PieChart : GraphicsView
{
    private double _angleSpan = 360D;
    public double AngleSpan 
    {
        get => _angleSpan;
        private set
        {
            _angleSpan = value;
            Debug.WriteLine("Invalidate");
            Invalidate();
        }
    }

    public PieChart() 
    {
        Drawable = new PieChartDrawable(this);

        Loaded += OnLoaded;
    }

    private void OnLoaded(object sender, EventArgs e)
    {
        Loaded -= OnLoaded;
        
        var animation = new Animation(v => AngleSpan = v, 0, 360D, Easing.CubicInOut);
        animation.Commit(this, "AngleAnimation", 8, 1500);
    }
}

出于测试的目的,我把Draw的内容去掉了,以为问题出在过于复杂的绘图上,但不管有没有内容,问题依旧。

public class PieChartDrawable : IDrawable
{
    private readonly PieChart _chart;

    public PieChartDrawable(PieChart chart) 
    { 
        _chart = chart;
    }

    public void Draw(ICanvas canvas, RectF dirtyRect)
    {
        Debug.WriteLine("Draw");
    }
}

我在附加和不附加调试器的情况下进行了测试(在调试和发布中),在所有情况下都是一样的。

我还没有在移动设备或模拟器上进行测试(仅在 Windows 项目上,因为这是我首先感兴趣的)。

【问题讨论】:

  • 您需要提供更多详细信息。如果你开始了一个动画,它不应该自己运行吗?我见过的例子没有明确的Invalidate。你在哪里打电话Invalidate?这是在 Windows 上进行的测试还是什么? [如果是移动模拟器,请在实际设备上测试。]您是否尝试过不使用调试器运行,看看它是否运行更顺畅?你是否做过最简单的测试:一个小的纯色对象,视图中没有其他内容?在我看来,有些东西正在导致Draw“花费太长时间”,因此在图形系统准备好再次绘制之前发生了多次无效。
  • 您可以查看此doc。它讲述了无效。您能否提供更多代码,以便我可以重现您描述的情况。
  • @JianweiSun 我知道文档的这一部分,正是这部分让我说从 GraphicsView 调用无效必然意味着从其 Drawable 调用 Draw。至于提供一段代码来重现问题,一切都在我的编辑中;只需将 PieChart 放在默认 maui 项目的 MainPage 上,运行它并在控制台中查看 Draw 方法没有被系统地调用(与文档所暗示的相反)。
  • @杰里米A。收到。顺便问一下,您是否尝试过生成.apk 文件并在实际设备上进行测试,看看它是否具有流畅的动画效果?
  • @JianweiSun奇怪的是,在物理android设备上,每次调用Invalidate方法都会触发重绘(并且动画很流畅)。我在不同的 PC 上进行了测试,看看我的问题是否来自我的配置(Rysen 7 5800 + RX6600 + 32GB ram),但问题出现在任何 Windows 机器(intel 或 amd,专用或集成 gpu)上。

标签: maui


【解决方案1】:

我终于找到了罪魁祸首;即我的屏幕。

如果我将屏幕的刷新率切换到 60Hz,我不再有任何问题(每次 Invalidate 时都会调用 Draw)。

基本上:

  • 60Hz -> 60fps
  • 165Hz -> 20~30fps

请注意,在 60Hz 中,我的应用程序中的一切都更加流畅,拖放、列表滚动等。这不仅限于我的画布故事。

我使用 WPF 和 UWP 应用程序进行了测试,我没有这种全局低刷新率问题。它看起来像 WinUI 端的一个错误。

这意味着在当前状态下,使用 WinUI(毛伊岛 Windows)应用程序的刷新率不可能超过 60 fps,并且如果最终用户拥有高刷新率屏幕,他的体验将大大降低.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-05
    • 2012-07-10
    • 1970-01-01
    • 2017-09-26
    • 1970-01-01
    • 2018-01-04
    • 1970-01-01
    相关资源
    最近更新 更多