UIStackView is useful for rapid streamlined content that you don’t want to worry about its layout. It’s like providing the content you want to show on the screen and let iOS deal with all the auto layout hassle.
The UIStackView class allows to build a simplified content in either a vertical or horizontal stack. Although UICollectionView can offer the same behaviour, sometimes you need a simplified screen rapidly set up instead of a UICollectionView flexible screen but complex to build.
Unlike UICollectionView, objects on the stack view don’t need a layout object to describe their sizes and inter-item spacing, you just add all the subviews to the stack view arrangedSubviews array property, and the UIStackView class will take care of the rest 🙂
In this tutorial, I will guide you through a step by step practical example to learn how to use the UIStackView class.
At the end of the tutorial, you will have been built a stack of image objects, each with their titles.
Download the starter project here.
Open up the project with Xcode 7, you will notice I have included some images to work with, and set up a top bar with two bar button items to add and remove images to the stack. You can see them by running the project so far.
Let’s start by adding the stack view object to the screen. From the object library, drag a Vertical Stack View object to the view scene. Resize it manually so it fits the whole space below the navigation bar.
Next, set up the top, leading, bottom and trailing constraints of the stack view to 0, so that it always fills in the remaining space in the view.
To finish up with the storyboard work, let’s hook up the stack view object as well as the two bar button actions to the code in order to use them.
To do so, switch to the Assistant editor, and make sure the storyboard file is loaded along with the ViewController.swift file in the editor.
Ctrl-drag from the left bar button to the ViewController.swift file, change the connection type to Action and name it “addImage”.
Next, ctrl-drag from the right bar button to the ViewController.swift file, set the connection type to Action, and name it “removeImage”.
Finally, ctrl-drag from the stack view object to the ViewController.swift file. This time just keep the connection type as Outlet and name it “stackView”.
You just hooked up the stack view outlet to manage it from within the code, and defined two action methods to add and remove content to the stack.
Now it’s time to write some code, switch back to the Standard editor, select the ViewController.swift file from the Project navigator, and add the following variable declaration just below the class name:
var dic = [String:String]()
The dictionary above will hold all the subviews names and content, in our case, it’s some image files names along with their titles.
Locate the viewDidLoad method and add the following code inside:
dic["Image 1"] = "Rape field in the landscape of Bohemian-Moravian Highlands, Czech Republic" dic["Image 2"] = "Norfolk Country Landscape" dic["Image 3"] = "Romania Country Landscape" dic["Image 4"] = "Japan Hokkaido Country Field"
The dic variable is of type dictionary, both the key and value of the dictionary are of type String. Of course you can change the type to something else, but here we intentionally put the key as String to reflect the image name at the same time, as done above.
In the same method, the viewDidLoad, place the following code (right after the above code):
for (image,name) in dic{ let imageView = UIImageView(image: UIImage(named: "\(image).jpg")) imageView.contentMode = .ScaleAspectFit let imageName = UILabel() imageName.text = name stackView.addArrangedSubview(imageView) stackView.addArrangedSubview(imageName) }
The code above will go over the dictionary items and iterate them one by one. It then set the image to an UIImageView container and the name to some label object. Finally, the code adds both the image view and the label to the stack content, this is done by calling the addArrangedSubview API which simply add the view in argument at the end of the arrangedSubviews array.
Note: Think about arrangedSubviews array as a list in which you add elements. The first element added to the array is the one to show at the top of the stack.
Run the project to see how it goes so far.
Only two images are visible in the stack and no title is shown. Although the content has been added correctly to the stack, you need to change the way the stack view object is displaying its subviews.
Select the stack view object from the scene, then from the Attributes inspector, select Fill Equally from the Distribution property enumeration list.
UIStackView arranges all its subviews along an axis, if the stack is vertically set up, then all subviews are displayed on the Y axis, and if horizontally set up, all the content is aligned on the X axis. By changing the distribution mode to Fill Equally, the stack object will use the UIStackViewDistributionFillEqually constant and hence resize all the arranged views so that they fill the available space along the stack view’s distribution axis.
Run the app, now all the views are displayed each with an equal height.
From the Attributes inspector, change the Alignment property to Center so that all subviews are centered horizontally along the distribution axis.
So far so good, let’s finish by implementing the two action methods you defined previously. Switch back to the ViewController.swift file, locate the addImage method and place the following code inside:
let rand = arc4random_uniform(4)+1 // Return a random int less than 4 let imageView = UIImageView(image: UIImage(named: "Image \(rand).jpg")) imageView.contentMode = .ScaleAspectFit let imageName = UILabel() imageName.text = dic["Image \(rand)"] UIView.animateWithDuration(0.45) { () -> Void in self.stackView.addArrangedSubview(imageView) self.stackView.addArrangedSubview(imageName) self.stackView.layoutIfNeeded() }
The code above will randomly select an item from the dictionary, a value from 0 to 3 which is the last item index in the dictionary. Then it will basically do the same work you did on the viewDidLoad method, instantiate an image view, set the image from the dictionary to its container with a label and add them to the stack view arrangedSubviews array, except this time you add the view with a nice animation 🙂
The layoutIfNeeded call is very important, and will force the layout update of the arranged views of the stack object after you added the subview.
Run the app and click on the left bar button from the navigation bar. Enjoy your work so far.
Let’s finish up by implementing the last action method to remove the subview from the stack arranged views array.
Locate the removeImage method and place the following code inside:
let v:UIView? = self.stackView.arrangedSubviews.last if let subview = v{ UIView.animateWithDuration(0.45) { () -> Void in subview.removeFromSuperview() self.stackView.layoutIfNeeded() } }
This should be familiar to you, the last view from the stack is being retrieved, then you remove it from its superview. By calling the removeFromSuperview API, the stack view object will automatically remove that subview from the arrangedSubviews array as well, so no need to call the removeArrangedSubview API explicitly.
That’s it, run the project and enjoy your work 🙂
As usual, you can download the final project here. Let me know your thoughts, questions, suggestions or anything else in the comment section below. I’d love to hear from you!
it is in swift 3 please upload source for swift 4