xamarin.forms - 如何在 SKCanvasView 上实现捏缩放和滑动?
问题描述
我正在使用 xamarin 表单开发图像查看器。我的源图像是无限大的,比我的视口大得多。所以我使用 SKCanvasView 控件逐部分绘制,以便我应该在图像中滑动。
我可以通过 SKCanvasView 上可用的 Touch 事件获得触摸点。在这里,我能够检测到双击。滑动和平移。
我无法决定何时向上/向下滑动多少图像需要向上/向下移动?
最初,我尝试将 SKCanvasView 放在 ScrollView 控件之上,并使用我正在绘制 SKCanvas 的滚动位置值。在这里滚动和打印完美。但是这里捏缩放不起作用,因为捏手势事件没有触发而是滚动。
解决方案
我曾经为我的一位朋友为 SKCanvas 做过类似的事情,尽管我个人从未使用过 Skia。
在任何情况下,它都有 Pinch、Pan 和 Tap 缩放事件,可以根据您的需要随意进行任何更改:
public class CustomSKCanvas : SKCanvasView
{
private const double MIN_SCALE = 1;
private const double MAX_SCALE = 4;
private const double OVERSHOOT = 0.15;
private double StartScale, LastScale;
private double StartX, StartY;
public CustomSKCanvas()
{
var pinch = new PinchGestureRecognizer();
pinch.PinchUpdated += OnPinchUpdated;
GestureRecognizers.Add(pinch);
var pan = new PanGestureRecognizer();
pan.PanUpdated += OnPanUpdated;
GestureRecognizers.Add(pan);
var tap = new TapGestureRecognizer { NumberOfTapsRequired = 2 };
tap.Tapped += OnTapped;
GestureRecognizers.Add(tap);
Scale = MIN_SCALE;
TranslationX = TranslationY = 0;
AnchorX = AnchorY = 0;
}
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
{
Scale = MIN_SCALE;
TranslationX = TranslationY = 0;
AnchorX = AnchorY = 0;
return base.OnMeasure(widthConstraint, heightConstraint);
}
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; //TODO tapped position
this.ScaleTo(MAX_SCALE, 250, Easing.CubicInOut);
}
}
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 void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
{
switch (e.Status)
{
case GestureStatus.Started:
LastScale = e.Scale;
StartScale = Scale;
AnchorX = e.ScaleOrigin.X;
AnchorY = e.ScaleOrigin.Y;
break;
case GestureStatus.Running:
if (e.Scale < 0 || Math.Abs(LastScale - e.Scale) > (LastScale * 1.3) - LastScale)
{ return; }
LastScale = e.Scale;
var 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;
}
}
private T Clamp<T>(T value, T minimum, T maximum) where T : IComparable
{
if (value.CompareTo(minimum) < 0)
return minimum;
else if (value.CompareTo(maximum) > 0)
return maximum;
else
return value;
}
}
祝你好运
在查询的情况下恢复。
推荐阅读
- groovy - Spock - 模拟方法不同的参数和不同的返回值
- qt - 当您的 qt quick 应用程序未运行时,如何在移动和桌面上显示通知?
- sql - 将 Xml 数据插入表时缺少选择关键字
- javascript - 覆盖单独文件 React Native 中的变量
- python-3.6 - 类型错误:需要一个类似字节的对象,而不是使用 kinit.stdin.write('%s\n' % password) 时的 'str'
- javascript - Using Promise Data from Async Await
- r - 如何将矩阵中的所有组合填充到两列
- python-3.x - cli 网络服务器上 Google Sheets API v4 的身份验证流程
- django - How can I reference a URL in Django settings.py
- java - Spring Boot inbuilt Tomcat Server - what is the advantage with respect of normal Spring app