5

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

dugla
  • 12,774
  • 26
  • 88
  • 136
  • So you want to stretch the image horizontally? if you dont zoom in the vertical axis, then the images will become skewed – coneybeare Sep 14 '09 at 18:21

3 Answers3

16

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];
}
Community
  • 1
  • 1
Brad Larson
  • 170,088
  • 45
  • 397
  • 571
  • 2
    this constraints the Y axis, but the UIScrollView behaves - during the pinch - as if both were transformed. That is the content offsets and content size are increased to merit the zoom on both axes. Any thoughts on what I might be missing? – Max MacLeod Jun 16 '15 at 20:38
1

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.

coneybeare
  • 33,113
  • 21
  • 131
  • 183
  • Thanks for this coneybeare. So that I'm sure I understand this method's usage, if I were to use the scrollview.bounds as the rect I would assume that would pin the dimensions of the view being scrolled to the dimensions of the scrollview, correct? Cheers, Doug – dugla Sep 14 '09 at 21:43
  • 1
    coneybeare, Actually, from the looks of your code snippet it appears you are handling all zooming since you are calling zoomToRect:animated yourself, rather than simply overriding it. I'd prefer to let UIScrollView handle all that and just insert my constraint. Will you approach require me to implement my own pan/zoom functionality. Could you provide a bit more enlightenment. Cheers, Doug – dugla Sep 14 '09 at 22:05
1

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.

Jeff
  • 2,659
  • 1
  • 22
  • 41