iOS Recipes - Matt Drance [46]
@implementation StaticPinsViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.gridView addNonScalingSubview:[self pinView]];
}
@end
Look closely as we zoom the view in this third tab: the pin does not resize itself, and it remains glued to its original point on the grid. How and why does this work? Well, let’s say the scroll view was zoomed to 2x. This would apply a 2x scale transform to the grid view and, by association, all of its subviews. Inverting that transform gives us a one-half (0.5x) scale. By applying the 0.5x scale to our pins, we have an effective 1x scale (2.0 from the superview, multiplied by 0.5 from our adjustment code).
There are some other cool benefits to this solution that you might not appreciate. First, the pin remains centered along its original position. This is due to the fact that transforms applied to views (and their underlying layers) work off the center rather than the origin. Second, the transform inversion works in both directions, zooming both in and out. It even works during the “bounce” animation when we exceed the scroll view’s minimum or maximum scale.
There are also some limitations. When using any of the animated UIScrollView zoom APIs, namely, ‑setZoomScale:animated: and ‑zoomToRect:animated:, the pins will not keep up with the animation—they momentarily scale along with the scroll view and quickly correct themselves when scrolling is over. This is because we don’t have direct access to the animation machinery inside UIScrollView and therefore can’t easily synchronize our own actions with it. This is a very small compromise that may not even be relevant to your application.
Recipe 22 Build a Carousel Paging Scroll View
Problem
You want to mimic the “carousel,” round-robin paging behavior in Apple’s Stocks app. You have a scroll view with a finite number of horizontal pages and need it to jump back around when scrolling past the end.
Solution
Jumping back around to the beginning or end of a list or array is pretty simple: just do some modulo arithmetic while adjusting your index, and you’ll come back around once you move out of bounds. Applying this behavior to UIScrollView, and making that behavior work “infinitely,” is a bit more complicated.
We’ll solve this problem by building on top of Apple’s PhotoScroller sample code from WWDC 2010. PhotoScroller demonstrates a number of interesting techniques on its own, including custom on-the-fly scroll view layout, tiled images, and reusable content views that work in a very similar fashion to table view cells. It’s a great starting foundation for the work we need to do.
PhotoScroller comes with three images, each with its own dedicated “page” in the scroll view gallery. However, it displays those photos in a linear slideshow fashion. You can’t scroll “backward” past the first image or “forward” beyond the last. In this recipe, we’ll apply some extra logic to circle back around when scrolling past either end of the collection. This will create an “infinite” scrolling effect similar to what we see in the built-in Stocks app on iPhone. Figure 27, Carousel behavior in a scroll view illustrates this behavior.
When paging past the last page, the scroll view comes right back around to the other side. It never stops at either end.
Figure 27. Carousel behavior in a scroll view
* * *
Before we get into the logic of circling around, we need to figure out how to create the illusion of infinite horizontal scrolling. The key word here is illusion. Since scrolling is determined by our scroll view’s contentSize property, we must have some finite value in place. What we’ll do, then, is choose a particularly large value that the user is unlikely to scroll to either end of in casual usage. We’ve chosen a value of 500,000, stored it in a macro for this recipe, and used it in the modified ‑contentSizeForPagingScrollView method. This gives us about 1,000 pages of horizontal scrolling space.
PhotoScroller Sample Code
The PhotoCarousel project included with this book is a modified version of Apple’s PhotoScroller