CATransform3D.MakeScale正在移动图层

时间:2018-07-17 08:26:15

标签: ios

我正在为iOS开发Xamarin.Forms应用程序。此应用程序由UIView组成,其中的子层为CALayers。它们是这样添加的:

// draw all the pins from the list
foreach (var pin in _control.PinsSource)
{
    var point = new CGPoint
    {
        X = pin.Longitude,
        Y = pin.Latitude
    };

    var shapeLayer = new CAShapeLayer
    {
        Name = nameof(MapItem),
        Path = MakeCircleAtLocation(point, PinRadius).CGPath,
        FillColor = UIColor.Red.CGColor
    };

    Layer.AddSublayer(shapeLayer);
}

// Create a UIBezierPath which is a circle at a certain location of a certain radius.
private static UIBezierPath MakeCircleAtLocation(CGPoint location, nfloat radius)
{
    var path = new UIBezierPath();
    path.AddArc(location, radius, 0, (float)(Math.PI * 2.0), true);
    return path;
}

然后我有一个UIPinchGestureRecognizer,它可以缩放UIView和其他GestureRecognizers,例如平移。

缩放和平移基本视图效果很好。 UIView使用称为_currentScale的变量缩放。在此处查看满量程方法:

private void HandlePinch(UIPinchGestureRecognizer recognizer)
{
    // Prevent the object to become too large or too small
    var newScale = (nfloat)Math.Max(MinZoomLevel, Math.Min(_currentScale * recognizer.Scale, MaxZoomLevel));

    if (_currentScale != newScale)
    {
        _currentScale = newScale;

        Transform = CGAffineTransform.MakeScale(_currentScale, _currentScale);

        foreach (var subLayer in Layer.Sublayers)
        {
            if (subLayer.Name == nameof(MapItem))
                subLayer.Transform = CATransform3D.MakeScale(PinRadius / _currentScale, PinRadius / _currentScale, 1);
        }
    }
    recognizer.Scale = 1;
}

如果子图层是地图图钉,我想使用_currentScale缩放比例,因此这就是为什么我使用PinRadius / _currentScale划分比例的原因。

缩放比例工作正常,但是图钉在地图上移动很奇怪。看到这里:

Screen recording

我该如何解决?

1 个答案:

答案 0 :(得分:0)

不幸的是,我找不到其他方法可以在每个紧要关头重新创建新的CAShapeLayer。非常丑陋,但是可以正常工作。

private void HandlePinch(UIPinchGestureRecognizer recognizer)
{
    // Prevent the object to become too large or too small
    var newScale = (nfloat)Math.Max(MinZoomLevel, Math.Min(_currentScale * recognizer.Scale, _maxZoomLevel));

    if (_currentScale != newScale)
    {
        _currentScale = newScale;
        _currentPinRadius = _pinRadius / _currentScale;

        Transform = CGAffineTransform.MakeScale(_currentScale, _currentScale);

        // First layer is a CALayer, so start at 1
        for (var i = 1; i < Layer.Sublayers.Length; i++)
        {
            var caLayer = ((CAShapeLayer)Layer.Sublayers[i]);

            var cgPoint = new CGPoint
            {
                X = _control.PinsSource[i - 1].Longitude,
                Y = _control.PinsSource[i - 1].Latitude
            };

            caLayer.Path = CreateCircle(cgPoint, _currentPinRadius);
        }
    }
    recognizer.Scale = 1;
}