gpt4 book ai didi

xamarin - Xamarin形式捏在一起并平移

转载 作者:行者123 更新时间:2023-12-03 13:45:09 29 4
gpt4 key购买 nike

我已经分别实现了平移和缩放,并且效果很好。我现在正尝试一起捏和平移,但遇到了一些问题。这是我的代码:

XAML:

<AbsoluteLayout x:Name="PinchZoomContainer">
<controls:NavBar x:Name="NavBar" ShowPrevNext="true" ShowMenu="false" IsModal="true" />
<controls:PanContainer x:Name="PinchToZoomContainer">
<Image x:Name="ImageMain" />
</controls:PanContainer>
</AbsoluteLayout>

捏/平手势添加:

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

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

平移方法:

void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
switch (e.StatusType)
{
case GestureStatus.Started:
startX = e.TotalX;
startY = e.TotalY;
Content.AnchorX = 0;
Content.AnchorY = 0;

break;
case GestureStatus.Running:
// Translate and ensure we don't pan beyond the wrapped user interface element bounds.
Content.TranslationX = Math.Max(Math.Min(0, x + e.TotalX), -Math.Abs(Content.Width - App.ScreenWidth));
Content.TranslationY = Math.Max(Math.Min(0, y + e.TotalY), -Math.Abs(Content.Height - App.ScreenHeight));
break;

case GestureStatus.Completed:
// Store the translation applied during the pan
x = Content.TranslationX;
y = Content.TranslationY;
break;
}
}

捏方法:

void OnPinchUpdated(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;
//ImageMain.AnchorX = 0;
//ImageMain.AnchorY = 0;
}
if (e.Status == GestureStatus.Running)
{
// Calculate the scale factor to be applied.
currentScale += (e.Scale - 1) * startScale;
currentScale = Math.Max(1, currentScale);
currentScale = Math.Min(currentScale, 2.5);
// 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;
}
}

如果我关闭任何一个手势而仅使用另一个手势,则该功能将完美运行。当我添加平移和捏合手势时,就会出现问题。似乎正在发生的事情是这样的:

1)平底锅实际上似乎按预期工作
2)最初在图像上平移时,假设将图像移动到Y中心和X中心,然后尝试缩放,则图像将恢复为初始状态。然后,当您平移时,它会将您移回尝试进行缩放之前的位置(这就是为什么我说平移可以正常工作的原因)。

从调试中了解到的是,缩放时并未考虑您当前所处的位置。因此,当您先平移然后缩放时,它不会缩放您所处的位置,而是缩放图像的起点。然后,当您尝试从那里进行平移时,平移方法仍会记住您所在的位置,并且它将您移回到尝试进行缩放之前的位置。

希望对此有所了解。显然,我的捏方法存在问题。我只是认为(显然无法弄清楚),我需要在其中添加考虑您当前所在位置的逻辑。

最佳答案

主要原因可能是每个人似乎都在复制和使用此代码(来自dev.xamarin网站),并使用了非常复杂且非常不必要的坐标计算方法(-)。不必要,因为我们可以使用恰好用于此目的的AnchorXAnchorY属性,简单地要求 View 为我们完成繁重的工作。

我们可以双击操作来放大并恢复到原始比例。请注意,由于Xamarin无法通过其Tap事件提供坐标值(实际上是非常不明智的决定),因此我们现在只能从中心缩放:

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

同样,捏手处理程序也很简单,根本不需要计算任何翻译。我们要做的就是将 anchor 设置到捏合起点,框架将完成其余工作,缩放将在该点周围进行。请注意,这里我们甚至还有一个额外的功能,即变焦比例两端的超调都具有弹性反弹。

private void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e) 
{
switch (e.Status)
{
case GestureStatus.Started:
StartScale = Scale;
AnchorX = e.ScaleOrigin.X;
AnchorY = e.ScaleOrigin.Y;
break;

case GestureStatus.Running:
double current = Scale + (e.Scale - 1) * StartScale;
Scale = Clamp(current, MIN_SCALE * (1 - OVERSHOOT), MAX_SCALE * (1 + OVERSHOOT));
break;

case GestureStatus.Completed:
if (Scale > MAX_SCALE)
this.ScaleTo(MAX_SCALE, 250, Easing.SpringOut);
else if (Scale < MIN_SCALE)
this.ScaleTo(MIN_SCALE, 250, Easing.SpringOut);
break;
}
}

以及平移处理程序,甚至更简单。在开始时,我们从 anchor 开始计算起点,而在平移过程中,我们会不断更改 anchor 。该 anchor 相对于 View 区域,我们可以轻松地将其固定在0到1之间,这样就可以完全停止平移,而无需进行任何平移计算。

private void OnPanUpdated(object sender, PanUpdatedEventArgs e) 
{
switch (e.StatusType)
{
case GestureStatus.Started:
StartX = (1 - AnchorX) * Width;
StartY = (1 - AnchorY) * Height;
break;

case GestureStatus.Running:
AnchorX = Clamp(1 - (StartX + e.TotalX) / Width, 0, 1);
AnchorY = Clamp(1 - (StartY + e.TotalY) / Height, 0, 1);
break;
}
}

所使用的常量和变量就是这些:

private const double MIN_SCALE = 1;
private const double MAX_SCALE = 8;
private const double OVERSHOOT = 0.15;
private double StartX, StartY;
private double StartScale;

关于xamarin - Xamarin形式捏在一起并平移,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40181090/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com