SwipeView
SwipeView is a class designed to simplify the implementation of horizontal, paged scrolling views on iOS. It is based on a UIScrollView, but adds convenient functionality such as a UITableView-style dataSource/delegate interface for loading views dynamically, and efficient view loading, unloading and recycling.
Install / Use
/learn @nicklockwood/SwipeViewREADME
Purpose
SwipeView is a class designed to simplify the implementation of horizontal, paged scrolling views on iOS. It is based on a UIScrollView, but adds convenient functionality such as a UITableView-style dataSource/delegate interface for loading views dynamically, and efficient view loading, unloading and recycling.
SwipeView's interface and implementation is based on the iCarousel library, and should be familiar to anyone who has used iCarousel.
Supported OS & SDK Versions
- Supported build target - iOS 7.0 (Xcode 5.0, Apple LLVM compiler 5.0)
- Earliest supported deployment target - iOS 5.0
- Earliest compatible deployment target - iOS 4.3
NOTE: 'Supported' means that the library has been tested with this version. 'Compatible' means that the library should work on this OS version (i.e. it doesn't rely on any unavailable SDK features) but is no longer being tested for compatibility and may require tweaking or bug fixes to run correctly.
ARC Compatibility
As of version 1.3, SwipeView requires ARC. If you wish to use SwipeView in a non-ARC project, just add the -fobjc-arc compiler flag to the SwipeView.m class. To do this, go to the Build Phases tab in your target settings, open the Compile Sources group, double-click SwipeView.m in the list and type -fobjc-arc into the popover.
If you wish to convert your whole project to ARC, comment out the #error line in SwipeView.m, then run the Edit > Refactor > Convert to Objective-C ARC... tool in Xcode and make sure all files that you wish to use ARC for (including SwipeView.m) are checked.
Thread Safety
SwipeView is derived from UIView and - as with all UIKit components - it should only be accessed from the main thread. You may wish to use threads for loading or updating SwipeView contents or items, but always ensure that once your content has loaded, you switch back to the main thread before updating the SwipeView.
Examples
Controls Example

Paging Example

Installation
To use the SwipeView class in an app, just drag the SwipeView class files (demo files and assets are not needed) into your project.
Properties
The SwipeView has the following properties:
@property (nonatomic, weak) IBOutlet id<SwipeViewDataSource> dataSource;
An object that supports the SwipeViewDataSource protocol and can provide views to populate the SwipeView.
@property (nonatomic, weak) IBOutlet id<SwipeViewDelegate> delegate;
An object that supports the SwipeViewDelegate protocol and can respond to SwipeView events and layout requests.
@property (nonatomic, readonly) NSInteger numberOfItems;
The number of items in the SwipeView (read only). To set this, implement the numberOfItemsInSwipeView: dataSource method. Note that not all of these item views will be loaded or visible at a given point in time - the SwipeView loads item views on demand as it scrolls.
@property (nonatomic, readonly) NSInteger numberOfPages;
The number of pages in the SwipeView (read only). To set this, implement the numberOfItemsInSwipeView: dataSource method and set the itemsPerPage value. If itemsPerPage = 1, numberOfPages will match the numberOfItems.
@property (nonatomic, readonly) CGSize itemSize;
The size of each item in the SwipeView. This property is read-only, but can be set using the swipeViewItemSize: delegate method.
@property (nonatomic, assign) NSInteger itemsPerPage;
The number of items per page when paging is enabled. Defaults to one;
@property (nonatomic, assign) BOOL truncateFinalPage;
If the number of items is not exactly divisible by the itemsPerPage value then it can result in blank space on the last page. By setting truncateFinalPage to YES, you can eliminate that space.
@property (nonatomic, strong, readonly) NSArray *indexesForVisibleItems;
An array containing the indexes of all item views currently loaded and visible in the SwipeView. The array contains NSNumber objects whose integer values match the indexes of the views. The indexes for item views start at zero and match the indexes passed to the dataSource to load the view.
@property (nonatomic, strong, readonly) NSArray *visibleItemViews;
An array of all the item views currently displayed in the SwipeView (read only). The indexes of views in this array do not match the item indexes, however the order of these views matches the order of the visibleItemIndexes array property, i.e. you can get the item index of a given view in this array by retrieving the equivalent object from the visibleItemIndexes array (or, you can just use the indexOfItemView: method, which is much easier).
@property (nonatomic, strong, readonly) UIView *currentItemView;
The first item view of the currently centered (or left-aligned, depending on the alignment value) page.
@property (nonatomic, readonly) NSInteger currentItemIndex;
The index of the first item of the currently centered (or left-aligned, depending on the alignment value) page. Setting this value is equivalent to calling scrollToItemAtIndex:duration: with the duration argument set to 0.0.
@property (nonatomic, assign) NSInteger currentPage;
The index of the currently centered (or left-aligned, depending on the alignment value) page. If itemsPerPage is equal to one, this value will match the currentItemIndex value. Setting this value is value is equivalent to calling scrollToPage:duration: with the duration argument set to 0.0.
@property (nonatomic, assign) SwipeViewAlignment alignment;
This property controls how the SwipeView items are aligned. The default value of SwipeViewAlignmentEdge means that the item views will extend to the edges of the SwipeView. Switching the alignment to SwipeViewAlignmentCenter means that the leftmost and rightmost item views will be centered when the SwipeView is fully scrolled to either extreme.
@property (nonatomic, assign, getter = isPagingEnabled) BOOL pagingEnabled;
Enables and disables paging. When paging is enabled, the SwipeView will stop at each item view as the user scrolls.
@property (nonatomic, assign, getter = isScrollEnabled) BOOL scrollEnabled;
Enables and disables user scrolling of the SwipeView. The SwipeView can still be scrolled programmatically if this property is set to NO.
@property (nonatomic, assign, getter = isWrapEnabled) BOOL wrapEnabled;
Enables and disables wrapping. When in wrapped mode, the SwipeView can be scrolled indefinitely and will wrap around to the first item view when it reaches past the last item. When wrap is enabled, the bounces property has no effect.
@property (nonatomic, assign, getter = isVertical) BOOL vertical;
This property toggles whether the SwipeView is displayed horizontally or vertically on screen.
@property (nonatomic, assign) BOOL delaysContentTouches;
This property works like the equivalent property of UIScrollView. It defers handling of touch events on subviews within the SwipeView so that embedded controls such as buttons do not interfere with the smooth scrolling of the SwipeView. Defaults to YES.
@property (nonatomic, assign) BOOL bounces;
Sets whether the SwipeView should bounce past the end and return, or stop dead.
@property (nonatomic, assign) float decelerationRate;
A floating-point value that determines the rate of deceleration after the user lifts their finger.
@property (nonatomic, readonly, getter = isDragging) BOOL dragging;
Returns YES if user has started scrolling the SwipeView and has not yet released it.
@property (nonatomic, readonly, getter = isDecelerating) BOOL decelerating;
Returns YES if the user isn't dragging the SwipeView any more, but it is still moving.
@property (nonatomic, readonly, getter = isScrolling) BOOL scrolling;
Returns YES if the SwipeView is currently being scrolled programatically.
@property (nonatomic, assign) BOOL defersItemViewLoading;
Sometimes when your SwipeView contains very complex item views, or large images, there can be a noticeable jerk in scrolling performance as it loads the new views. Setting the defersItemViewLoading property to YES forces the SwipeView to defer updating the currentItemIndex property and loading of new item views until after the scroll has finished. This can result in visible gaps in the SwipeView if you scroll too far in one go, but for scrolling short distances you may find that this improves animation performance.
@property (nonatomic, assign) CGFloat autoscroll;
This property can be used to set the SwipeView scrolling at a constant speed. A value of 1.0 would scroll the SwipeView forwards at a rate of one item per second. The autoscroll value can be positive or negative and defaults to 0.0 (stationary). Autoscrolling will stop if the user interacts with the SwipeView, and will resume when they stop.
Methods
The SwipeView class has the following methods:
- (void)reloadData;
This reloads all SwipeView item views from the dataSource and refreshes the display. Note that reloadData will reset the currentItemIndex back to zero, so if you want to retain the current scroll position, make a note of currentItemIndex before reloading and restore it afterwards. If you just wish to refresh the visible items without changing the number of items, consider calling reloadItemAtIndex: on all visible items instead.
- (void)reloadItemAtIndex:(NSInteger)index;
This method will reload the specified item view. The new item will be requested from the dataSource. Off-screen views will not be reloaded.
- (void)scrollByNumberOfItems:(NSInteger)itemCount duration:(NSTimeInterval)duration;
This method allows you to scroll the SwipeView by a fixed distance, measured in item widths. Posi
