Xamarin.forms 如何实现收缩缩放&;在SKCanvasView上滑动?

Xamarin.forms 如何实现收缩缩放&;在SKCanvasView上滑动?,xamarin.forms,skiasharp,Xamarin.forms,Skiasharp,我正在使用xamarin表单开发图像查看器。我的源图像是无限大的,比我的视口大得多。所以我使用SKCanvasView控件逐部分绘制,这样我就可以浏览图像了 我可以通过SKCanvasView上提供的触摸事件获得触摸点。在这里,我能够检测到双击。滑动和平移 我无法决定何时向上/向下滑动需要向上/向下移动多少图像 最初,我尝试将SKCanvasView放置在ScrollView控件的顶部,并使用绘制SKCanvas时使用的滚动位置值。这里的滚动和打印工作完美。但在这里,捏缩缩放不起作用,因为捏缩手

我正在使用xamarin表单开发图像查看器。我的源图像是无限大的,比我的视口大得多。所以我使用SKCanvasView控件逐部分绘制,这样我就可以浏览图像了

我可以通过SKCanvasView上提供的触摸事件获得触摸点。在这里,我能够检测到双击。滑动和平移

我无法决定何时向上/向下滑动需要向上/向下移动多少图像


最初,我尝试将SKCanvasView放置在ScrollView控件的顶部,并使用绘制SKCanvas时使用的滚动位置值。这里的滚动和打印工作完美。但在这里,捏缩缩放不起作用,因为捏缩手势事件没有触发,而是滚动。

我曾经为我的一个朋友为SKCanvas做过类似的事情,尽管我个人从未使用过Skia

在任何情况下,它都有捏、平移和点击缩放事件,您可以根据需要随意进行任何更改:

 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;
    }
}
公共类CustomSKCanvas:SKCanvasView
{
私人常数双最小刻度=1;
私人常数双最大刻度=4;
专用常数双超调=0.15;
私人双星标度,最新标度;
私人双星;
公共定制画布()
{
var pinch=新的PinchGestureRecognitor();
pinch.PinchUpdated+=OnPinchUpdated;
手势识别器。添加(捏);
var pan=新的PangestureRecognitor();
pan.PanUpdated+=OnPanUpdated;
手势识别器。添加(平移);
var tap=新的TapGestureRecognitor{NumberOfTapsRequired=2};
抽头。抽头+=无抽头;
手势识别器。添加(轻触);
刻度=最小刻度;
TranslationX=TranslationY=0;
AnchorX=AnchorY=0;
}
测量时受保护的覆盖大小请求(双宽度约束、双高度约束)
{
刻度=最小刻度;
TranslationX=TranslationY=0;
AnchorX=AnchorY=0;
返回base.OnMeasure(宽度约束、高度约束);
}
私有void OnTapped(对象发送方,事件参数e)
{
如果(比例>最小比例)
{
这个.ScaleTo(最小刻度,250,放松.CubicInOut);
这个.TranslateTo(0,0250,Easing.CubicInOut);
}
其他的
{
AnchorX=AnchorY=0.5;//TODO分接位置
此.ScaleTo(最大刻度,250,宽松.CubicInOut);
}
}
私有void OnPanUpdated(对象发送方,PanUpdatedEventArgs e)
{
开关(如状态类型)
{
案例手势状态。已启动:
StartX=(1-锚点)*宽度;
星形=(1-锚定)*高度;
打破
案例手势状态。正在运行:
锚具=夹具(1-(StartX+e.TotalX)/宽度,0,1);
锚定=夹具(1-(起点+e.TotalY)/高度,0,1);
打破
}
}
PinchUpdated上的私有void(对象发送方,PinchEstureUpdatedEventArgs e)
{
开关(如状态)
{
案例手势状态。已启动:
LastScale=e.刻度;
StartScale=比例;
AnchorX=e.ScaleOrigin.X;
AnchorY=e.ScaleOrigin.Y;
打破
案例手势状态。正在运行:
如果(e.Scale<0 | | Math.Abs(LastScale-e.Scale)>(LastScale*1.3)-LastScale)
{return;}
LastScale=e.刻度;
无功电流=标度+(e.标度-1)*标准标度;
刻度=钳位(电流、最小刻度*(1-超调)、最大刻度*(1+超调));
打破
案例管理状态。已完成:
如果(比例>最大比例)
这个.ScaleTo(最大刻度,250,放松.SpringOut);
else if(刻度<最小刻度)
这个.ScaleTo(MIN_SCALE,250,Easing.SpringOut);
打破
}
}
专用T形夹(T值,T最小值,T最大值),其中T:I可比较
{
如果(值比较到(最小值)<0)
返回最小值;
如果(值比较(最大值)>0)
返回最大值;
其他的
返回值;
}
}
祝你好运

如有疑问,请回复