【问题标题】:Image flickering while zooming while using PinchGestureRecognizer使用 PinchGestureRecognizer 进行缩放时图像闪烁
【发布时间】:2021-05-29 05:34:09
【问题描述】:

我使用下面的代码放置<Image><Image.GestureRecognizers> 以实现缩放功能。 还提供了事件PinchUpdated="PinchGestureRecognizer_PinchUpdated" 背后的代码。 缩放功能有效,但捏合时闪烁过多。

XAML:

            <Image 
                Grid.Column="0" 
                Grid.Row="0"
                x:Name="pageIterator"
                Grid.ColumnSpan="3">
                <Image.GestureRecognizers>
                    <PinchGestureRecognizer PinchUpdated="PinchGestureRecognizer_PinchUpdated"></PinchGestureRecognizer>
                </Image.GestureRecognizers>
            </Image>

背后的代码:

        private void PinchGestureRecognizer_PinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
        {
            double currentScale = 1;
            double startScale = 1;
            double xOffset = 0;
            double yOffset = 0;

            if (e.Status == GestureStatus.Started)
            {
                // Store the current scale factor applied to the wrapped user interface element,
                // and zero the components for the center point of the translate transform.
                startScale = Content.Scale;
                Content.AnchorX = 0;
                Content.AnchorY = 0;
            }
            if (e.Status == GestureStatus.Running)
            {
                // Calculate the scale factor to be applied.
                currentScale += (e.Scale - 1) * startScale;
                currentScale = Math.Max(1, currentScale);

                // The ScaleOrigin is in relative coordinates to the wrapped user interface element,
                // so get the X pixel coordinate.
                double renderedX = Content.X + xOffset;
                double deltaX = renderedX / Width;
                double deltaWidth = Width / (Content.Width * startScale);
                double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;

                // The ScaleOrigin is in relative coordinates to the wrapped user interface element,
                // so get the Y pixel coordinate.
                double renderedY = Content.Y + yOffset;
                double deltaY = renderedY / Height;
                double deltaHeight = Height / (Content.Height * startScale);
                double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;

                // Calculate the transformed element pixel coordinates.
                double targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
                double targetY = yOffset - (originY * Content.Height) * (currentScale - startScale);

                // Apply translation based on the change in origin.
                Content.TranslationX = targetX.Clamp(-Content.Width * (currentScale - 1), 0);
                Content.TranslationY = targetY.Clamp(-Content.Height * (currentScale - 1), 0);

                // Apply scale factor.
                Content.Scale = currentScale;
            }
            if (e.Status == GestureStatus.Completed)
            {
                // Store the translation delta's of the wrapped user interface element.
                xOffset = Content.TranslationX;
                yOffset = Content.TranslationY;
            }
        }


【问题讨论】:

    标签: c# xamarin xamarin.forms zooming pinchzoom


    【解决方案1】:

    您应该将下面的行移出PinchGestureRecognizer_PinchUpdated 方法,否则每次触发时您实际上都是在初始化这些值。

    double currentScale = 1;
    double startScale = 1;
    double xOffset = 0;
    double yOffset = 0;
    
    private void PinchGestureRecognizer_PinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
        {
            if (e.Status == GestureStatus.Started)
            {
                // Store the current scale factor applied to the wrapped user interface element,
                // and zero the components for the center point of the translate transform.
                startScale = Content.Scale;
                Content.AnchorX = 0;
                Content.AnchorY = 0;
            }
            if (e.Status == GestureStatus.Running)
            {
                // Calculate the scale factor to be applied.
                currentScale += (e.Scale - 1) * startScale;
                currentScale = Math.Max(1, currentScale);
    
                // The ScaleOrigin is in relative coordinates to the wrapped user interface element,
                // so get the X pixel coordinate.
                double renderedX = Content.X + xOffset;
                double deltaX = renderedX / Width;
                double deltaWidth = Width / (Content.Width * startScale);
                double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;
    
                // The ScaleOrigin is in relative coordinates to the wrapped user interface element,
                // so get the Y pixel coordinate.
                double renderedY = Content.Y + yOffset;
                double deltaY = renderedY / Height;
                double deltaHeight = Height / (Content.Height * startScale);
                double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;
    
                // Calculate the transformed element pixel coordinates.
                double targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
                double targetY = yOffset - (originY * Content.Height) * (currentScale - startScale);
    
                // Apply translation based on the change in origin.
                Content.TranslationX = targetX.Clamp(-Content.Width * (currentScale - 1), 0);
                Content.TranslationY = targetY.Clamp(-Content.Height * (currentScale - 1), 0);
    
                // Apply scale factor.
                Content.Scale = currentScale;
            }
            if (e.Status == GestureStatus.Completed)
            {
                // Store the translation delta's of the wrapped user interface element.
                xOffset = Content.TranslationX;
                yOffset = Content.TranslationY;
            }
        }
    

    【讨论】:

    • currentScale 应该是if (e.Status == GestureStatus.Running) 范围内的局部变量。
    • @Liron 不行,也应该在方法外,其实每次触发的时候,都会先触发PinchGestureRecognizer_PinchUpdated,然后再进入if(),如果放到里面方法作为局部变量,你可以看到它每次仍然从value1开始。你可以测试一下,把它作为局部变量放在里面,然后在if (e.Status == GestureStatus.Running)里面调用Console.WriteLine("Current:=" + currentScale);,你会看到控制台1每次。
    • @LeoZhu-MSFT,我会在这里检查并更新。我在猜测初始化,但由于我是新手,我认为在开始时是必不可少的。
    • @LeoZhu-MSFT 它适用于放大(放大时)。但是当缩小时(恢复正常大小时),它又会闪烁。这意味着我必须将一些代码移到外面......
    • @LeoZhu-MSFT 好吧,我正在检查 Xamarin Demo PinchGesture,希望我能清楚地看到代码。我会更新的。
    猜你喜欢
    • 2018-03-11
    • 2019-06-06
    • 1970-01-01
    • 2017-09-17
    • 1970-01-01
    • 2012-08-30
    • 2012-09-26
    • 2023-03-25
    • 2010-09-16
    相关资源
    最近更新 更多