Creating Image Slider with UIKit APIs
Thanks to Nick Lockwood's book iOS Animation Advanced Techniques. I was able to write another implementation of Image slider. I wrote an image slider couple years back using UIScrollView
for which I had to write manual routine to slide images back and forth. However, this time I used techniques iOS offered which made my task easier than before.
Using iOS to do animation means I,
- Don't have to write complex animation routine
- No need to go into mathematics to compute offset and position of an individual image
- No need to scroll
UIScrollView
manually - Add extra animations to image transition with Apple built in types
I have hosted this library on Github. Excellent part of this is, it is written fully in Swift which makes it future proof too.
Here's a little demo with image slider animation,
Below are the features listed.
-
Ability to pass an array of
UIImage
objects which will be displayed on the view -
Ability to pass an array of
NSURL
objects which will then be downloaded from the network and shown asynchronously -
Ability to specify default placeholder image
Usage
Image slider is simply an UIView
subclass, so you can use it like any other UIView
subclass. You can embed it into your parent view and either set manual frames or add constraints.
The library provides two very similar initializers with most of the parameters set to default value so that client does not specifically need to mention all the parameters while initializing ImageSliderView
With local images,
let imageSliderView = JKImageSliderView(images: [UIImage(named: "girlRunning")!, UIImage(named: "changeColor")!, UIImage(named: "donald")!, UIImage(named: "cone")!], transitionType: kCATransitionPush, placeholderImage: UIImage(named: "placeholder"), showBullets: true)
With remote image URLs
let imageSliderView = JKImageSliderView(imageURLs: [NSURL(string: "https://pbs.twimg.com/profile_images/738744285101580288/OUoCVEXG.jpg")!, NSURL(string: "http://www.mapsofindia.com/images2/india-map.jpg")!], transitionType: kCATransitionPush, placeholderImage: UIImage(named: "placeholder"), showBullets: true)
Here is the explanation of customizable parameters,
-
images - An array of
UIImage
objects -
URLs - An array of
NSURL
objects -
transitionType - Types of images transitions. Possible values are,
- kCATransitionFade
- kCATransitionMoveIn
- kCATransitionPush
- kCATransitionReveal
Effects of all these transition types are added to the demo project.
-
imageAnimationDuration - A image animation transition duration. Time it takes to change from one image to another
-
showBulletView - A flag which indicates whether to show bullet view or not. Bullet view is shown by default. It looks like below,
- swipeEnabled - Indicates whether user can swipe to trigger the image transitions. Swipe gesture is disabled by default.
Getting callback when image is swiped
If client app wants to get callback for image swipe action, you can get it by confirming to following protocol,
protocol JKSliderViewDelegate: class {
func indexChanged(to newIndex: Int)
}
Then setup the UIImageSliderView
delegate to the client class in which this slider view is added, and implement the method.
imageSliderView?.delegate = self
func indexChanged(to newIndex: Int) {
print("Slider index changed to \(newIndex)")
}
Brief Overview
This is the brief overview of how this library actually works,
// First we create the instance of `CATransition` and add appropriate properties to it,
let swipeViewTransition = CATransition()
swipeViewTransition.duration = 0.75
// How transition should occur. Possible types are listed above.
swipeViewTransition.type = kCATransitionPush
// Indicates how transition should occur. Since we are using image slider, possible types could be kCATransitionFromLeft or kCATransitionFromRight depending on the direction from which image is slid.
swipeViewTransition.subtype = kCATransitionFromLeft
// Add animation to our imageView instance
swipeImageView.layer.addAnimation(swipeViewTransition, forKey: kCATransition)
// To perform image transition, we maintain a variable named currentImageIndex. Which will keep the track of index corresponding to current image on the viewport.
// For swipe left action
currentImageIndex = currentImageIndex - 1
currentImageIndex = ((currentImageIndex % imagesCount) + imagesCount) % imagesCount
// For swipe right action
// imagesCount is an internal variable computed directly from the number of images passed to the initializer.
currentImageIndex = currentImageIndex + 1
currentImageIndex = ((currentImageIndex % imagesCount) + imagesCount) % imagesCount
// We then update the image on the viewport depending on whether we passed plain UIImage objects or remote image URLs.
if imageType == .ImageTypeURL {
swipeImageView.sd_setImageWithURL(imageURLs[currentImageIndex], placeholderImage: placeHolder, options: .HighPriority)
} else {
swipeImageView.image = images[currentImageIndex]
}
// Call the delegate if one is already setup.
if let delegate = delegate {
delegate.indexChanged(to: currentImageIndex)
}
// Change the highlighted bullet to suitable index.
self.bulletView?.moveToIndex(currentImageIndex)
Cocoapods
This library supports integration into project through Cocoapods. Just add following line to your podfile
and run pod update
or pod install
if pods are not already installed.
platform :ios, '8.0'
inhibit_all_warnings!
use_frameworks!
xcodeproj '<xcodeproj_file_name>'
target '<xcodeproj_file_name>' do
pod 'JKImageSliderView', :git => 'git@github.com:jayesh15111988/JKImageSliderView.git', :tag => '0.1'/:branch => 'master'
end
For some reason I was not able to make a delegate
and protocol visible to Objective-C code. My understanding is this happens if Swift type is non-bridgeable to Objective-C code. It works perfectly fine in Swift code though. If anyone has any idea why, I would appreciate their input
As usual, any comments, questions, concerns or PRs are welcome. I am looking forward to hear from you soon.