UIView. How do I constrain scaling to one dimensio

2019-01-18 16:22发布

问题:

I have an instance of UIScrollview containing an instance of UIView. The UIView is just a container for a horizonal array of UIImageView instances. - Zooming is provided by UIScrollView and UIScrollViewDelegate. I would like to constrain zooming to occur only along the horizontal axis with no vertical scalling at all. How to I do this?

Is there a way, for example, to subclass UIView and override the appropriate method to prevent vertical scaling? I like this approach but I am unclear on which method to override and what that overridden method should actually do.

Cheers, Doug

回答1:

Similar to what I describe in this answer, you can create a UIView subclass and override the -setTransform: accessor method to adjust the transform that the UIScrollView will try to apply to your UIView. Set this UIView to host your content subviews and make it the subview of the UIScrollView.

Within your overridden -setTransform:, you'll need to take in the transform that the UIScrollView would like to apply and adjust it so that the scaling only takes effect in one direction. From the documentation on how CGAffineTransform matrices are constructed, I believe the following implementation should constrain your scaling to be just along the horizontal direction:

- (void)setTransform:(CGAffineTransform)newValue;
{
 CGAffineTransform constrainedTransform = CGAffineTransformIdentity;
 constrainedTransform.a = newValue.a;
 [super setTransform:constrainedTransform];
}


回答2:

Using OS 3.0, you can tell the zoom to zoom to a rect in the scrollview. I have this in my logic that detects taps.

CGRect zoomRect = [self zoomRectForScale:newScale withCenter:CGPointMake(tapPoint.x, tapPoint.y) inScrollView:scrollView];
[scrollView zoomToRect:zoomRect animated:YES];

The for the other part, you will have to stretch your image views by the ratio that the new frame has against the original, and center it in the same center point. You can do this in an animation timed the same as the zoom animation so that it looks right, but I think this will be the only way to do it.



回答3:

In scrollViewDidZoom:, adjust your content view's variables based on zoomScale, reset zoomScale to 1.0, then do setNeedsDisplay on the content view. Handle the actual zoom (in whatever direction you want) in your content view's drawRect:.

The Ugly Details:

  1. While the zoom is in progress, the UIScollView changes contentOffset and contentScale, so save those prior values in scrollViewWillBeginZooming: and in scrollViewDidZoom: so you can compute a new contentOffset yourself according to the zoom.

  2. Since changing zoomScale will immediately fire another scrollViewDidZoom:, you must set a BOOL before (and clear after) resetting the zoomScale. Test the BOOL at the start of scrollViewDidZoom: and return if true.

  3. You may need to inhibit scrollViewDidScroll: while the zoom is in progress (test a BOOL; set it in scrollViewWillBeginZooming: and clear it in scrollViewDidEndZooming:) so your own contentOffsets are used while the zoom is in progress.