如何在放大和缩小xamarin表单中的内容页面时启用滚动

时间:2018-04-11 09:42:33

标签: c# xamarin xamarin.forms

我正在尝试使用xamarin.forms放大和缩小内容页面。 我可以放大和缩小但问题是滚动不起作用。 我想缩放图像。使用此代码缩放工作完美。但是在缩放时我无法看到完整的图像。我必须滚动才能查看图像的其余部分。因为我需要滚动。但是滚动不起作用。

XAML

xmlns:helper="clr-namespace:KPGTC.Deals.Mobile.Helpers"
<helper:PinchToZoomContainer>
    <helper:PinchToZoomContainer.Content>
        <Image x:Name="img_Popup"/>
    </helper:PinchToZoomContainer.Content>
</helper:PinchToZoomContainer>

代码:

public class PinchToZoomContainer : ContentView
{
    double MIN_SCALE = 1;
    double MAX_SCALE = 4;
    double startScale = 1;
    double currentScale = 1;
    double xOffset = 0;
    double yOffset = 0;
    bool _isActive = false;

    public PinchToZoomContainer()
    {
        DependencyService.Get<IHelpers>().ShowAlert("Double-tap to zoom");

        //var _pinchGesture = new PinchGestureRecognizer();
        //_pinchGesture.PinchUpdated += OnPinchUpdated;
        //GestureRecognizers.Add(_pinchGesture);

        var _tapGesture = new TapGestureRecognizer { NumberOfTapsRequired = 2 };
        _tapGesture.Tapped += On_Tapped;
        GestureRecognizers.Add(_tapGesture);

        var _panGesture = new PanGestureRecognizer();
        _panGesture.PanUpdated += OnPanUpdated;
        GestureRecognizers.Add(_panGesture);

        TranslationX = 0;
        TranslationY = 0;
        _isActive = false;
    }

    private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
    {
        if (_isActive)
        {
            if (e.TotalX > 0)
            {
                if (e.TotalX > 2)
                {
                    TranslationX += 15;
                }
            }
            else
            {
                if (e.TotalX < -2)
                {
                    TranslationX -= 15;
                }
            }
        }
    }

    private void On_Tapped(object sender, EventArgs e)
    {
        if (Scale > MIN_SCALE)
        {
            _isActive = false;
            this.ScaleTo(MIN_SCALE, 250, Easing.CubicInOut);
            this.TranslateTo(0, 0, 250, Easing.CubicInOut);
        }
        else
        {
            _isActive = true;
            AnchorX = AnchorY = 0.5;
            this.ScaleTo(MAX_SCALE, 250, Easing.CubicInOut);
        }
    }

    void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
    {
        if (e.Status == GestureStatus.Started)
        {
            startScale = Content.Scale;
            Content.AnchorX = 0;
            Content.AnchorY = 0;
        }
        if (e.Status == GestureStatus.Running)
        {
            currentScale += (e.Scale - 1) * startScale;
            currentScale = Math.Max(1, currentScale);

            double renderedX = Content.X + xOffset;
            double deltaX = renderedX / Width;
            double deltaWidth = Width / (Content.Width * startScale);
            double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;

            double renderedY = Content.Y + yOffset;
            double deltaY = renderedY / Height;
            double deltaHeight = Height / (Content.Height * startScale);
            double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;

            double targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
            double targetY = yOffset - (originY * Content.Height) * (currentScale - startScale);

            Content.TranslationX = targetX.Clamp(-Content.Width * (currentScale - 1), 0);
            Content.TranslationY = targetY.Clamp(-Content.Height * (currentScale - 1), 0);

            Content.Scale = currentScale;
        }
        if (e.Status == GestureStatus.Completed)
        {
            xOffset = Content.TranslationX;
            yOffset = Content.TranslationY;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

好吧,这是一个非常艰难的,不可否认,我完全不理解我是如何做到的,但我做到了。

一些想法:

  • 你混合了容器和内容的翻译,这很难处理 - 如果这是可能的话
  • 平移时,每次引发pan事件时都添加15,但有更好的方法:只需存储内容的初始偏移量,然后添加TotalX和{{1}分别到内容的TotalYTranslationX(这是容易的部分)
  • 在缩放时进行平移是很难做到的,我不得不通过反复试验找到它
    • 基本上你必须在手势开始时存储捏手势的原点并计算原始原点和当前原点之间的差异
    • 然后你必须添加diff(分别乘以控件的with和height)到目标翻译

以下是平移的代码:

TranslationY

这里是为了捏

private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
    if (e.StatusType == GestureStatus.Started)
    {
        this.xOffset = this.Content.TranslationX;
        this.yOffset = this.Content.TranslationY;
    }

    if (e.StatusType != GestureStatus.Completed
        && e.StatusType != GestureStatus.Canceled)
    {
        this.Content.TranslationX = this.xOffset + e.TotalX;
        this.Content.TranslationY = this.yOffset + e.TotalY;
    }

    if (e.StatusType == GestureStatus.Completed)
    {
        this.xOffset = this.Content.TranslationX;
        this.yOffset = this.Content.TranslationY;
    }
}

(当然你必须在课堂上添加void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e) { if (e.Status == GestureStatus.Started) { this.startScale = this.Content.Scale; this.Content.AnchorX = 0; this.Content.AnchorY = 0; this.startScaleOrigin = e.ScaleOrigin; } if (e.Status == GestureStatus.Running) { var originDiff = PinchToZoomContainer.CalculateDiff(e.ScaleOrigin, this.startScaleOrigin); this.currentScale += (e.Scale - 1) * this.startScale; this.currentScale = Math.Max(1, this.currentScale); double renderedX = this.Content.X + this.xOffset; double deltaX = renderedX / this.Width; double deltaWidth = this.Width / (this.Content.Width * this.startScale); double originX = (this.startScaleOrigin.X - deltaX) * deltaWidth; double renderedY = this.Content.Y + this.yOffset; double deltaY = renderedY / this.Height; double deltaHeight = this.Height / (this.Content.Height * this.startScale); double originY = (startScaleOrigin.Y - deltaY) * deltaHeight; double targetX = this.xOffset - ((originX) * this.Content.Width) * (this.currentScale - this.startScale) - originDiff.X * this.Content.Width; double targetY = this.yOffset - ((originY) * this.Content.Height) * (this.currentScale - this.startScale) - originDiff.Y * this.Content.Height; this.Content.TranslationX = targetX.Clamp(-this.Content.Width * (this.currentScale - 1), 0); this.Content.TranslationY = targetY.Clamp(-this.Content.Height * (this.currentScale - 1), 0); this.Content.Scale = this.currentScale; } if (e.Status == GestureStatus.Completed) { this.xOffset = this.Content.TranslationX; this.yOffset = this.Content.TranslationY; } } )。

最后,您需要使用该方法计算两点之间的距离

Point startScaleOrigin

不幸的是,我没有设法正确使用,但我认为你应该能够从这里找到答案。