You have content that needs to get displayed on the screen, but it requires more real estate than what the device’s screen allows for.
Scroll views are one of the features that make iOS a really neat operating system. They are practically everywhere. You’ve been to the Clock or the Contacts apps, haven’t you? Have you seen how the content can be scrolled up and down? Well, that’s the magic of scroll views.
There really is one basic concept you need to learn about scroll
views: the content size, which lets the scroll view
conform to the size of what it’s displaying. The content size is a value of type CGSize
that specifies the width and the height
of the contents of a scroll view. A scroll view, as its name implies, is a subclass of
UIView
, so you can simply add your
views to a scroll view using its addSubview:
method. However, you need to make
sure that the scroll view’s content size is set properly; otherwise, the
contents inside the scroll view won’t
scroll.
As an example, let’s find a big image and load it to an image
view. I will add the same image that I used in Recipe 1.22: a MacBook Air image. I
will add it to an image view and place it in a scroll view. Then I will
use the contentSize
of the scroll
view to make sure this content size is equal to the size of the image
(width and height). First, let’s start with the implementation file of our view
controller:
#import "ViewController.h"
@interface
ViewController
()
@property
(
nonatomic
,
strong
)
UIScrollView
*
myScrollView
;
@property
(
nonatomic
,
strong
)
UIImageView
*
myImageView
;
@end
@implementation
ViewController
And let’s place the image view inside the scroll view:
-
(
void
)
viewDidLoad
{
[
super
viewDidLoad
];
UIImage
*
imageToLoad
=
[
UIImage
imageNamed
:
@"MacBookAir"
];
self
.
myImageView
=
[[
UIImageView
alloc
]
initWithImage
:
imageToLoad
];
self
.
myScrollView
=
[[
UIScrollView
alloc
]
initWithFrame
:
self
.
view
.
bounds
];
[
self
.
myScrollView
addSubview
:
self
.
myImageView
];
self
.
myScrollView
.
contentSize
=
self
.
myImageView
.
bounds
.
size
;
[
self
.
view
addSubview
:
self
.
myScrollView
];
}
If you now load up the app in iOS Simulator, you will see that you can scroll the image horizontally and vertically. The challenge here, of course, is to provide an image that is bigger than the screen’s boundaries. For example, if you provide an image that is 20×20 pixels, the scroll view won’t be of much use to you. In fact, it would be wrong to place such an image into a scroll view, as the scroll view would practically be useless in that scenario. There would be nothing to scroll because the image is smaller than the screen size.
One of the handy features of UIScrollView
is support for delegation, so
that it can report really important events to the app through a
delegate. A delegate for a scroll view must conform to the UIScrollViewDelegate
protocol. Here are some
of the methods defined in this protocol:
scrollViewDidScroll:
Gets called whenever the contents of a scroll view get scrolled.
scrollViewWillBeginDecelerating:
Gets called when the user scrolls the contents of a scroll view and lifts his finger off the screen as the scroll view scrolls.
scrollViewDidEndDecelerating:
Gets called when the scroll view has finished scrolling its contents.
scrollViewDidEndDragging:willDecelerate:
Gets called when the user finishes dragging the contents of the scroll view. This method is very similar to the
scrollViewDidEndDecelerating:
method, but you need to bear in mind that the user can drag the contents of a scroll view without scrolling the contents. She can simply put her finger on the content, move her finger to any location on the screen and lift her finger, without giving the contents any momentum to move. This is dragging as opposed to scrolling. Scrolling is similar to dragging, but the user will give momentum to the contents’ movement by lifting her finger off the screen while the content is being dragged around, and not waiting for the content to stop before lifting her finger off the screen. Dragging is comparable to holding down the accelerator in a car or pedaling on a bicycle, whereas scrolling is comparable to coasting in a car or on a bicycle.
So let’s add some fun to our previous app. Now the goal is to set
the alpha level of the image inside our image view to 0.50f (half
transparent) when the user starts to scroll the scroll view and set this
alpha back to 1.0f (opaque) when the user finishes scrolling. Let’s
begin by conforming to the UIScrollViewDelegate
protocol:
#import "ViewController.h"
@interface
ViewController
()
<
UIScrollViewDelegate
>
@property
(
nonatomic
,
strong
)
UIScrollView
*
myScrollView
;
@property
(
nonatomic
,
strong
)
UIImageView
*
myImageView
;
@end
@implementation
ViewController
Then let’s implement this functionality:
-
(
void
)
scrollViewDidScroll:
(
UIScrollView
*
)
scrollView
{
/* Gets called when user scrolls or drags */
self
.
myScrollView
.
alpha
=
0.50f
;
}
-
(
void
)
scrollViewDidEndDecelerating:
(
UIScrollView
*
)
scrollView
{
/* Gets called only after scrolling */
self
.
myScrollView
.
alpha
=
1.0f
;
}
-
(
void
)
scrollViewDidEndDragging:
(
UIScrollView
*
)
scrollView
willDecelerate:
(
BOOL
)
decelerate
{
/* Make sure the alpha is reset even if the user is dragging */
self
.
myScrollView
.
alpha
=
1.0f
;
}
-
(
void
)
viewDidLoad
{
[
super
viewDidLoad
];
UIImage
*
imageToLoad
=
[
UIImage
imageNamed
:
@"MacBookAir"
];
self
.
myImageView
=
[[
UIImageView
alloc
]
initWithImage
:
imageToLoad
];
self
.
myScrollView
=
[[
UIScrollView
alloc
]
initWithFrame
:
self
.
view
.
bounds
];
[
self
.
myScrollView
addSubview
:
self
.
myImageView
];
self
.
myScrollView
.
contentSize
=
self
.
myImageView
.
bounds
.
size
;
self
.
myScrollView
.
delegate
=
self
;
[
self
.
view
addSubview
:
self
.
myScrollView
];
}
As you might have noticed, scroll views have indicators. An indicator is the little tracking line that appears on the sides of a scroll view when its contents are getting scrolled and moved. Figure 1-63 shows an example.
Indicators simply show the user where the current view is in
relation to the content (top, halfway down, etc.). You can control what
the indicators look like by changing the value of the indicatorStyle
property. For instance, here I
have changed the indicator style of my scroll view to white:
self
.
myScrollView
.
indicatorStyle
=
UIScrollViewIndicatorStyleWhite
;
One of the great features of scroll views is that they allow pagination. Pagination is the same as scrolling, but locks the scrolling when the user moves to the next page. You have perhaps already seen this if you’ve ever used the Photos app on the iPhone or iPad. When you are looking at photos, you can swipe between them. Each swipe brings the next or previous photo onto the screen. Your swiping never scrolls all the way to the end or all the way to the start. When the scrolling starts, the scroll view detects the next image to display, scrolls and bounces to that image, and stops the scrolling animation. That’s pagination. If you haven’t tried it already, I urge you to do so, because otherwise I could go on and on and none of this would make sense unless you looked at an app that supports pagination.
For this example code, I’ve prepared three images: an iPhone, an
iPad, and a MacBook Air. I’ve placed them in their individual image
views and added them to a scroll view. Then we can enable pagination by
setting the value of the pagingEnabled
property of the scroll view to
YES
:
-
(
UIImageView
*
)
newImageViewWithImage:
(
UIImage
*
)
paramImage
frame:
(
CGRect
)
paramFrame
{
UIImageView
*
result
=
[[
UIImageView
alloc
]
initWithFrame
:
paramFrame
];
result
.
contentMode
=
UIViewContentModeScaleAspectFit
;
result
.
image
=
paramImage
;
return
result
;
}
-
(
void
)
viewDidLoad
{
[
super
viewDidLoad
];
UIImage
*
iPhone
=
[
UIImage
imageNamed
:
@"iPhone"
];
UIImage
*
iPad
=
[
UIImage
imageNamed
:
@"iPad"
];
UIImage
*
macBookAir
=
[
UIImage
imageNamed
:
@"MacBookAir"
];
CGRect
scrollViewRect
=
self
.
view
.
bounds
;
self
.
myScrollView
=
[[
UIScrollView
alloc
]
initWithFrame
:
scrollViewRect
];
self
.
myScrollView
.
pagingEnabled
=
YES
;
self
.
myScrollView
.
contentSize
=
CGSizeMake
(
scrollViewRect
.
size
.
width
*
3.0f
,
scrollViewRect
.
size
.
height
);
[
self
.
view
addSubview
:
self
.
myScrollView
];
CGRect
imageViewRect
=
self
.
view
.
bounds
;
UIImageView
*
iPhoneImageView
=
[
self
newImageViewWithImage
:
iPhone
frame:
imageViewRect
];
[
self
.
myScrollView
addSubview
:
iPhoneImageView
];
/* Go to next page by moving the x position of the next image view */
imageViewRect
.
origin
.
x
+=
imageViewRect
.
size
.
width
;
UIImageView
*
iPadImageView
=
[
self
newImageViewWithImage
:
iPad
frame:
imageViewRect
];
[
self
.
myScrollView
addSubview
:
iPadImageView
];
/* Go to next page by moving the x position of the next image view */
imageViewRect
.
origin
.
x
+=
imageViewRect
.
size
.
width
;
UIImageView
*
macBookAirImageView
=
[
self
newImageViewWithImage
:
macBookAir
frame:
imageViewRect
];
[
self
.
myScrollView
addSubview
:
macBookAirImageView
];
}
Now we have three pages of scrollable content (Figure 1-64).
Get iOS 7 Programming Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.