UIScrollView setZoomScale sets the applied rotatio

2019-06-20 08:44发布

问题:

I've been working on a maps replacement for quite a while now. The whole thing works with a UIScrollView backed by a CATiledLayer.

To rotate my map, i rotate the layer itself. (Using CATransform3DMakeRotation) Works pretty well so far =)

But if I ever call setZoomScale method the CATransform3D that is going to be submitted to my layer is resetting the rotation to 0.

My question is, is there any way to set the zoomscale of my scrollView without loosing the applied rotation?

The same problem exists for the pinch gestures.

//Additional Infos

To rotate around the current Position, i have to edit the anchor point. Maybe this is a problem for the scaling, too.

- (void)correctLayerPosition {
    CGPoint position    = rootView.layer.position;
    CGPoint anchorPoint = rootView.layer.anchorPoint;
    CGRect  bounds      = rootView.bounds;
    // 0.5, 0.5 is the default anchorPoint; calculate the difference
    // and multiply by the bounds of the view
    position.x              = (0.5 * bounds.size.width) + (anchorPoint.x - 0.5) *    bounds.size.width;
    position.y              = (0.5 * bounds.size.height) + (anchorPoint.y - 0.5) * bounds.size.height;
    rootView.layer.position = position;
}

- (void)onFinishedUpdateLocation:(CLLocation *)newLocation {
    if (stayOnCurrentLocation) {
        [self scrollToCurrentPosition];
    }
    if (rotationEnabled) {
        CGPoint anchorPoint        = [currentConfig layerPointForLocation:newLocation];
        anchorPoint.x              = anchorPoint.x / rootView.bounds.size.width;
        anchorPoint.y              = anchorPoint.y / rootView.bounds.size.height;
        rootView.layer.anchorPoint = anchorPoint;
        [self correctLayerPosition];
    }
}

回答1:

You can implement scrollViewDidZoom: delegate method and concatenate the two transforms to achieve desired effect:

- (void) scrollViewDidZoom:(UIScrollView *) scrollView
{
    CATransform3D scale = contentView.layer.transform;
    CATransform3D rotation = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);

    contentView.layer.transform = CATransform3DConcat(rotation, scale);
}

EDIT

I've got simpler idea! How about adding another view to the hierarchy with the rotation transform attached? Here's the proposed hierarchy:

  • ScrollView
    • ContentView - the one returned by viewForZoomingInScrollView:
      • RotationView - the one with rotation transform
        • MapView - the one with all the tiles

I don't think that performance should be any concern here and it's worth trying.