Circular UIScrollView – SwiftCarousel
ArticleOften times when you have some type of scrollable gallery, and there are plenty of images, you wish the gallery will start again just by swiping to the next image. Unfortunately, most of the time you have to go back by scrolling X times back just to see the first image. It is kinda painful and can be easily fixed. Let me introduce SwiftCarousel.
SwiftCarousel is a lightweight, written natively in Swift, infinite (circular) UIScrollView. It has basic functionality like setting up by code or by Interface Builder, using different type of views with different sizes (which was lacking in the other libraries), but also some advanced functionality like:
- Selecting items by tap (which you can disable) and setting default selected item
- Delegate protocol in which you can implement methods like didSelectItem(), didDeselectItem() and others
- Showing specific number of items or aligning views as they are (with resizing or without)
Today we will show how you could use it.
Animalove – Simple app to select favorite animal.
Starting off with Example1, we will create circular scroll view for self-sizing UILabels. First, create new project (I was using Xcode 7.2, but it should work properly on earlier versions that handle Swift). We will use Single View Application for iOS, and we will use Swift without any additional fireworks. If you don’t need help with configuring project, just skip to Step 3.
Now we need to add SwiftCarousel to our project. We can do it by installing it from cocoapods adding this line to Podfile:
1 | pod "SwiftCarousel" |
After downloading the carousel class, we can now start writing some code. Setting up is as easy as creating view (in IB or code, we will show you how to do it in Storyboard, but Example2 shows how to do it with code).
Step 1 – Add View to your ViewController
Add a View to your controller (place it wherever you want), set width & height, and what is most important here, set class as SwiftCarousel (if Xcode doesn’t see the SwiftCarousel class, please check if you installed your pods right or if the code you copied is correct).
Step 2 – Connect your View with ViewController
Next step would be to connect your View with ViewController. We will use Assistant Editor, press and hold ctrl and using mouse we will drag it to the ViewController as an outlet.
Step 3 – Add your items to the carousel!
Now we will just add our items to the carousel. In our example we will use UILabels which will self-size based on the font and text.
First, we will write a simple function that will create label based on the text:
1 2 3 4 5 6 7 8 9 10 | func labelForString(string: String) -> UILabel { let text = UILabel() text.text = string text.textColor = .blackColor() text.textAlignment = .Center text.font = .systemFontOfSize(24.0) text.numberOfLines = 0 return text } |
Then we will just setup our carousel with animal names as UILabels. Configuration will be done in viewDidLoad():
1 2 3 4 5 6 7 8 | override func viewDidLoad() { super.viewDidLoad() let items = ["Elephants", "Tigers", "Chickens", "Owls", "Rats", "Parrots", "Snakes"] let itemsViews = items.map { labelForString($0) } carousel.items = itemsViews carousel.resizeType = .FloatWithSpacing(10.0) } |
What is important here is the resizeType. When we don’t set resizeType as .FloatWithSpacing(CGFloat) or .VisibleItemsPerPage(Int), we get default type which is .WithoutResizing(CGFloat). What it does is, it will place your views as they are – and our views don’t have any frames at all – so we will see blank page. But because we want our labels to fit our text, we will use .FloatWithSpacing(10.0). It translates to: “Just use .sizeToFit() on every UIView and then place it with correct frames. Also add spacing between them (which is 10 points in our case).”.
And thats it! It was really easy, wasn’t it?
Now you can configure your carousel as you want. For instance with default selected index:
1 | carousel.defaultSelectedIndex = 3 |
Or implement didSelectItem() delegate method:
1 2 3 4 5 6 7 8 9 | func didSelectItem(item item: UIView, index: Int) -> UIView? { if let animal = item as? UILabel { animal.textColor = UIColor.redColor() return animal } return item } |
But then you need to set the delegate property for carousel:
1 | carousel.delegate = self |
There are more delegate methods which you can implement:
1 2 3 4 5 6 7 | @objc public protocol SwiftCarouselDelegate { optional func didSelectItem(item item: UIView, index: Int) -> UIView? optional func didDeselectItem(item item: UIView, index: Int) -> UIView? optional func didScroll(toOffset offset: CGPoint) -> Void optional func willBeginDragging(withOffset offset: CGPoint) -> Void optional func didEndDragging(withOffset offset: CGPoint) -> Void } |
Every method is optional so you can implement what you what you want!
Also you can select your item from code and with animation (or not):
1 | carousel.selectItem(1, animated: true) // Selects index 1 with animation |
You can find complete source code on Droids on Roids’s GitHub repository
About the author
Ready to take your business to the next level with a digital product?
We'll be with you every step of the way, from idea to launch and beyond!
Hi, I used this carousel and it worked perfectly, saved me lot of time and effort. Thank you!
I have a question, is there any way to programmatically scroll to a specific item? I used the ‘carousel.selectItem(1, animated: true)’ to select an item on viewDidLoad, the item is selected but it is not in the middle of the visible scroll area so user gets confuse about which item is selected. Is there any method/property which can solve my problem?
Thanks
To do this in
viewDidLoad
you can set thedefaultSelectedIndex
property. Later you can do it byselectItem(_:animated:)
as you stated above. So the example of setting the default index would be:carousel.defaultSelectedIndex = 1
Cheers.
Hey!
To do this in viewDidLoad you can set the defaultSelectedIndex property. Later you can do it by selectItem(_:animated:) as you stated above. So the example of setting the default index would be:
carousel.defaultSelectedIndex = 1
Cheers.
I want to ask in Example 2 is there any way images should be autoscroll after every 15 second?
Hey! There is no built-in method that we’ve made, but you can use NSTimer that will do a task every 15 second, and the task would select the next item using method selectItem(:animated). You should be also aware that you might try to select to the index that is lower than 0 or index that is higher than the amount of items in carousel, so you have to be sure to make the conditional statements.
My requirement like,
Carousal A
Carousal B
I designed with two view and assigned tag value to them.
I cannot determine which carousal actually clicked, could you add it yourself?
I added your source file as manually, not using pod file, then i dragged view and assigned class so far good after that i am trying to add UILable by following code”
try! carousal.itemsFactory(itemsCount: 7) { choice in
let labelFrame = CGRect(origin: .zero, size: CGSize(width: 100.0, height: 40.0))
let contView = UIView(frame: labelFrame)
let label = UILabel(frame: labelFrame)
label.text = daysArray[Int(choice)]
label.textColor = UIColor.white
label.textAlignment = .center
contView.addSubview(label)
return contView
}
But its never executed, its crashing out of block with out any crash log. any idea?
It happens only when adding files as manually.