Online Book Reader

Home Category

iOS Recipes - Matt Drance [45]

By Root 214 0
view in action. We now have the opposite problem: the red pin no longer moves as the grid scales, but it now scales its size while zooming. This isn’t what we want either. The scaling occurs because it was added as a subview of the grid, and the grid itself was scaled.

What we want is for the pin to stay still and stay the same size at all times. What’s left to try?

First, let’s discuss what happens when zooming occurs in a scroll view. As the user zooms on a scroll view, the scroll view’s zoomScale property changes. As a result, the “zooming view” returned by ‑viewForZoomingInScrollView: receives a corresponding change to its transform property. The trick with transforms is that their effects are naturally inherited by subviews. This is why the pin in the Zooming Pins tab was scaling: our grid view, as the view for zooming, received a new transform that affected the pin’s own scale.

Another thing that changes as zooming occurs is the scroll view’s contentSize: larger as we zoom in; smaller as we zoom out. When the pin was a subview of the scroll view, set to an origin of, say, (10,10), that origin became a much less substantial dent in the content area as zooming occurred and the content size increased. This made it look like the pin in the Moving Pins tab was moving offscreen, when in fact we were simply focusing on a finer, more distant section of the scroll view’s content.

So, how do we solve this problem? How do we get the benefits of both approaches but none of the drawbacks? The trick lies in the transform we mentioned earlier. If we could just invert the grid’s transform and apply that inversion to the pins, then we could force the pins to stay their original size. Luckily, the CGAffineTransform API lets us do just that. So, we’ll keep the pins as subviews of the grid and adjust its transform on the fly while zooming occurs.

But wait a minute. What if we have a complex hierarchy in our zooming view and we want only some of them to behave this way while the rest scale up and down along with everything else? We’ll need a way to identify the nonzooming subviews. This is where PRPGridView’s superclass, PRPScrollContentView, comes in. It’s a very basic view that defines a set of subviews we want to keep static. These special “nonscaling” views will still be added as subviews, but they’ll also be added to a set so we can keep track of which views we need to adjust.

ScrollViewPins/Classes/PRPScrollContentView.h

@interface PRPScrollContentView : UIView {}

@property (nonatomic, readonly, retain) NSMutableSet *nonScalingSubviews;

- (void)addNonScalingSubview:(UIView *)view;

@end

A convenience setter method, ‑addNonScalingSubview:, both adds the passed view to the hierarchy and flags it for exclusion from scaling, so our calling code doesn’t need to remember both steps.

ScrollViewPins/Classes/PRPScrollContentView.m

- (void)addNonScalingSubview:(UIView *)view {

[self.nonScalingSubviews addObject:view];

[self addSubview:view];

}

With our subset of special views clearly defined, we go to work by overriding ‑setTransform: to call an adjustment routine for all of our nonscaling subviews.

ScrollViewPins/Classes/PRPScrollContentView.m

- (void)setTransform:(CGAffineTransform)transform {

[super setTransform:transform];

[self adjustSubviewsForTransform:transform];

}

This adjustment process is simple: invert the container’s transform, which was set as a result of zooming, and apply that inverted transform to each subview we don’t want scaled.

ScrollViewPins/Classes/PRPScrollContentView.m

- (void)adjustSubviewsForTransform:(CGAffineTransform)transform {

CGAffineTransform inversion = CGAffineTransformInvert(transform);

for (UIView *subview in self.nonScalingSubviews) {

subview.transform = inversion;

}

}

We wire up this new functionality by passing the pin view to ‑addNonScalingSubview: instead of ‑addSubview:. You can see this in the StaticPinsViewController class, and you can see the results by selecting the Static Pins tab in the demo app.

ScrollViewPins/Classes/Demo View Controllers/StaticPinsViewController.m

Return Main Page Previous Page Next Page

®Online Book Reader