• Home   /  
  • Archive by category "1"

Uicollectionview Section Index Titles For Essays

Mission accomplished

Each app starts off the same way: a few screens, some buttons, and maybe a list or two. But as time goes on and the app grows, features start to creep their way in. Your clean data sources start to crumble under the pressure of deadlines and product managers. After a while, you’re left with the massive-view-controller ruins to maintain. Adopt IGListKit today to ease some of that burden!

IGListKit was created to make feature-creep and massive-view-controllers a thing of the past when working with . By creating lists with IGListKit, you can build apps with decoupled components, blazing-fast updates, and support for any type of data.

In this tutorial you will refactor a basic to use IGListKit, then extend the app and take it out of this world!

Getting Started

You are one of NASA’s top software engineers and on staff for the latest manned mission to Mars. The team already built the first version of the Marslink app which you can download here. After the project is downloaded, open Marslink.xcworkspace and run the app.

So far, the app simply shows a list of astronaut journal entries.

You’re tasked with adding features to this app whenever the crew needs new features. Familiarize yourself with the project by opening the Marslink\ViewControllers\ClassicFeedViewController.swift and having a look around. If you’ve ever worked with , what you see looks pretty standard:

  • is a subclass that implements in an extension.
  • creates a , registers cells, sets the data source, and adds it to the view hierarchy.
  • The array powers the number of sections, each having just two cells (one for the date, one for the text).
  • Date cells are configured with the Sol date and text entry cells with text.
  • returns a fixed size for the date cell and calculates the size of the text for the actual entry.

Everything seems to be working just fine, but the mission director comes with some urgent product update requests:

An astronaut has just been stranded on Mars. We need you to add a weather module and realtime chat. You have 48 hours.

Engineers from JPL have some of these systems working, but they need your help putting them into the app.

If all the pressure of bringing an astronaut home wasn’t enough, NASA’s head designer just handed you requirements that each subsystem’s update in the app has to be animated, which means no reloadData().

How in the world are you supposed to integrate these new modules into an existing app and make all the transitions animated? The astronaut only has so many potatoes!

Introducing IGListKit

While is an incredibly powerful tool, with great power comes great responsibility. Keeping your data source and the view in sync is of utmost importance, and crashes are commonly caused by disconnects here.

IGListKit is a data-driven framework built by the team at Instagram. With this framework, you provide an array of objects to display in the . For each type of object an adapter creates something called a section controller, which has all of the details for creating cells.

IGListKit automatically diffs your objects and performs animated batch updates on the for whatever changed. This way you never have to write batch updates yourself, avoiding the issues listed under caveats here.

Replacing a UICollectionView with IGListKit

IGListKit does all the hard work of identifying changes in a collection and updating the appropriate rows with animation. It is also structured to easily handle multiple sections with different data and UI. With that in mind, it is a perfect solution to the new batch of requirements – so it’s time to start implementing it!

With Marslink.xcworkspace still open, right-click on the ViewControllers group and select New File…. Add a new Cocoa Touch Class that subclasses named FeedViewController.

Open AppDelegate.swift and find the method. Find the line that pushes onto the navigation controller and replace it with this:

nav.pushViewController(FeedViewController(), animated: false)

is now the root view controller. You’ll keep ClassicFeedViewController.swift around for reference, but is where you’ll implement the new IGListKit powered collection view.

Build and run and make sure a new, empty view controller shows up on screen.

Adding the Journal loader

Open FeedViewController.swift and add the following property to the top of :

let loader = JournalEntryLoader()

is a class that loads hard-coded journal entries into an array.

Add the following to the bottom of :

loader.loadLatest()

is a method that loads the latest journal entries.

Adding the collection view

It’s time to start adding some IGListKit specific controls to the view controller. Before you do, you need to import the framework. Near the top of FeedViewController.swift add a new import:

import IGListKit

Note: The project in this tutorial uses CocoaPods to manage dependencies. IGListKit is written in Objective-C, so if you manually add it to your project you’ll need to into your bridging header

Add an initialized constant to the top of :

// 1 let collectionView: IGListCollectionView = { // 2 let view = IGListCollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout()) // 3 view.backgroundColor = UIColor.black return view }()
  1. IGListKit uses , which is a subclass of , which patches some functionality and prevents others.
  2. This starts with a zero-sized rect since the view isn’t created yet. It uses the just as the did.
  3. The background color is set to the NASA-approved black.

Add the following to the bottom of :

view.addSubview(collectionView)

This adds the new to the controller’s view.

Below , add the following:

override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() collectionView.frame = view.bounds }

is overridden, setting the frame to match the bounds.

IGListAdapter and data source

With , you need some sort of data source that adopts . Its job is to return section and row counts as well as individual cells.

In IGListKit, you use what is called an to control the collection view. You still need a data source that conforms to the protocol , but instead of returning counts and cells, you provide arrays and section controllers (more on this later).

For starters, in FeedViewController.swift add the following at the top of :

lazy var adapter: IGListAdapter = { return IGListAdapter(updater: IGListAdapterUpdater(), viewController: self, workingRangeSize: 0) }()

This creates a lazily-initialized variable for the . The initializer requires three parameters:

  1. is an object conforming to IGListUpdatingDelegate, which handles row and section updates. is a default implementation that is suitable for your usage.
  2. is a that houses the adapter. This view controller is later used for navigating to other view controllers.
  3. is the size of the working range, which allows you to prepare content for sections just outside of the visible frame.

Note: Working ranges are a more advanced topic not covered by this tutorial. However there is plenty of documentation and even an example app in the IGListKit repo!

Add the following to the bottom of :

adapter.collectionView = collectionView adapter.dataSource = self

This connects the to the . It also sets as the for the adapter — resulting in a compiler error because you haven’t adopted the protocol yet.

Fix this by extending to adopt . Add the following to the bottom of the file:

extension FeedViewController: IGListAdapterDataSource { // 1 func objects(for listAdapter: IGListAdapter) -> [IGListDiffable] { return loader.entries } // 2 func listAdapter(_ listAdapter: IGListAdapter, sectionControllerFor object: Any) -> IGListSectionController { return IGListSectionController() } // 3 func emptyView(for listAdapter: IGListAdapter) -> UIView? { return nil } }

now adheres to and implements its three required methods:

  • returns an array of data objects that should show up in the collection view. is provided here as it contains the journal entries.
  • For each data object, must return a new instance of a section controller. For now you’re returning a plain to appease the compiler — in a moment, you’ll modify this to return a custom journal section controller.
  • returns a view that should be displayed when the list is empty. NASA is in a bit of a time crunch, so they didn’t budget for this feature.

Creating Your First Section Controller

A section controller is an abstraction that, given a data object, configures and controls cells in a section of a collection view. This concept is similar to a view-model that exists to configure a view: the data object is the view-model, and the cells are the view. The section controller acts as the glue between the two.

In IGListKit, you create a new section controller for different types of data and behavior. JPL engineers already built a model, so you need to create a section controller that can handle it.

Right-click on the SectionControllers group and select New File…. Create a new Cocoa Touch Class named JournalSectionController that subclasses IGListSectionController.

Xcode doesn’t automatically import third-party frameworks, so in JournalSectionController.swift add a line at the top:

import IGListKit

Add the following properties to the top of :

var entry: JournalEntry! let solFormatter = SolFormatter()

is a model class that you’ll use when implementing the data source. The class provides methods for converting dates to Sol format. You’ll need both shortly.

Also inside , override by adding the following:

override init() { super.init() inset = UIEdgeInsets(top: 0, left: 0, bottom: 15, right: 0) }

Without this, the cells between sections will butt up next to each other. This adds a 15 point padding to the bottom of objects.

Your section controller needs to conform to the protocol before it can be used in IGListKit. Start by adding the following extension to the bottom of the file:

extension JournalSectionController: IGListSectionType { func numberOfItems() -> Int { return 2 } func sizeForItem(at index: Int) -> CGSize { return .zero } func cellForItem(at index: Int) -> UICollectionViewCell { return UICollectionViewCell() } func didUpdate(to object: Any) { } func didSelectItem(at index: Int) {} }

Note: IGListKit makes heavy use of required protocol methods. Though you might end up with empty methods, or ones that return , you don’t have to suffer from silently missing methods or fight a dynamic runtime. It makes using IGListKit very hard to mess up.

You’ve implemented the protocol’s four required methods.

All methods are stubbed out implementations except for — which simply returns 2 for a date and text pair. You can refer back to and notice that you also return 2 items-per-section in . This is basically the same thing!

In , add the following:

entry = object as? JournalEntry

is used to hand an object to the section controller. Note this method will always be called before any of the cell protocol methods. Here, you save the passed object in .

Note: Objects can change multiple times during the lifetime of a section controller. This only happens when you start unlocking more advanced features of IGListKit like custom model diffing. You wont have to worry about diffing in this tutorial.

Now that you have some data, you can start configuring your cells. Replace the placeholder implementation of with the following:

// 1 let cellClass: AnyClass = index == 0 ? JournalEntryDateCell.self : JournalEntryCell.self // 2 let cell = collectionContext!.dequeueReusableCell(of: cellClass, for: self, at: index) // 3 if let cell = cell as? JournalEntryDateCell { cell.label.text = "SOL \(solFormatter.sols(fromDate: entry.date))" } else if let cell = cell as? JournalEntryCell { cell.label.text = entry.text } return cell

is called when a cell is required at a given index in the section. Here’s what you do inside:

  1. If the index is the first, use a cell, otherwise use cell. Journal entries always appear with a date followed by the text.
  2. Dequeue the cell from the reuse pool using the cell class, a section controller (), and the index.
  3. Depending on the cell type, configure it using the you set earlier in .

Next, replace the placeholder implementation of with the following:

// 1 guard let context = collectionContext, let entry = entry else { return .zero } // 2 let width = context.containerSize.width // 3 if index == 0 { return CGSize(width: width, height: 30) } else { return JournalEntryCell.cellSize(width: width, text: entry.text) }
  1. The is a variable and must be nullable. Though it should never be , it’s best to take precaution, and Swift makes that simple!
  2. is a context object with information about the adapter, collection view, and view controller that is using the section controller. Here you need to get the width of the container.
  3. If the first index (a date cell), return a size as wide as the container and 30 points tall. Otherwise, use the cell helper method to calculate the dynamic text size of the cell.

The last method is , which is called whenever someone taps on a cell. It’s a required method so you must add it, but since you aren’t doing anything when tapped just leave it empty.

This pattern of dequeuing a cell of different types, configuring, and returning sizes should all feel familiar if you’ve ever worked with before. Again, you can refer back to and see that a lot of this code is almost exactly the same!

Now you have a section controller that receives a object and returns and sizes two cells. It’s time to bring it all together.

Back in FeedViewController.swift, replace the contents of with the following:

return JournalSectionController()

Your new journal section controller is now returned when this method is called.

Build and run the app. You should see a list of journal entries!

Adding Messages

JPL engineering is pretty happy that you got the refactor done so quickly, but they really need to establish communication with the stranded astronaut. They’ve asked you to integrate the messaging module ASAP.

Before you add any views, you first need the data.

Open FeedViewController.swift and add a new property to the top of :

let pathfinder = Pathfinder()

acts as a messaging system, and represents the physical Pathfinder rover the astronaut dug up on Mars.

Locate in your extension and modify the contents to match the following:

var items: [IGListDiffable] = pathfinder.messages items += loader.entries as [IGListDiffable] return items

You might recall that this method provides data source objects to your . The modification here adds the to to provide messages for a new section controller.

Note: You have to cast the array of messages simply to make the Swift compiler happy. The objects already conform to .

Right-click the SectionControllers group to create a new subclass named MessageSectionController. Add the IGListKit import to the top:

import IGListKit

With the compiler happy, you’ll leave the rest unchanged for now.

Go back to FeedViewController.swift and update in the extension so it appears as follows:

if object is Message { return MessageSectionController() } else { return JournalSectionController() }

This now returns the new message section controller if the data object is of type .

The JPL team wants you to try and setup with the following requirements:

  • Receives a
  • Has a bottom inset of 15 points
  • Returns a single cell sized using the function
  • Dequeues and configures a using the object’s and values to populate labels.

Give it a shot! The team drafted up a solution below in case you need help.

Solution Inside: MessageSectionControllerSelectShow
import IGListKit class MessageSectionController: IGListSectionController { var message: Message! override init() { super.init() inset = UIEdgeInsets(top: 0, left: 0, bottom: 15, right: 0) } } extension MessageSectionController: IGListSectionType { func numberOfItems() -> Int { return 1 } func sizeForItem(at index: Int) -> CGSize { guard let context = collectionContext else { return .zero } return MessageCell.cellSize(width: context.containerSize.width, text: message.text) } func cellForItem(at index: Int) -> UICollectionViewCell { let cell = collectionContext?.dequeueReusableCell(of: MessageCell.self, for: self, at: index) as! MessageCell cell.messageLabel.text = message.text cell.titleLabel.text = message.user.name.uppercased() return cell } func didUpdate(to object: Any) { message = object as? Message } func didSelectItem(at index: Int) {} }

Once you’re ready, build and run to see messages integrated in the feed!

Weather on Mars

Our astronaut needs to be able to get the current weather in order to navigate around things like dust storms. JPL built another module that displays the current weather. There’s a lot of information in there though, so they ask that the weather only display when tapped.

Create one last section controller named WeatherSectionController. Start the class off with an initializer and some variables:

import IGListKit class WeatherSectionController: IGListSectionController { // 1 var weather: Weather! // 2 var expanded = false override init() { super.init() // 3 inset = UIEdgeInsets(top: 0, left: 0, bottom: 15, right: 0) } }
  1. This section controller will receive a object in .
  2. is a used to track if the weather section is expanded or not. It is initialized to so the detail cells are initially collapsed.
  3. Just like the other sections, use a bottom inset of 15 points.

Now add an extension to conform to , as well as implementing three of the required methods:

extension WeatherSectionController: IGListSectionType { // 1 func didUpdate(to object: Any) { weather = object as? Weather } // 2 func numberOfItems() -> Int { return expanded ? 5 : 1 } // 3 func sizeForItem(at index: Int) -> CGSize { guard let context = collectionContext else { return .zero } let width = context.containerSize.width if index == 0 { return CGSize(width: width, height: 70) } else { return CGSize(width: width, height: 40) } } }
  1. In , you save the passed object.
  2. If the weather is expanded, returns five cells that will contain different pieces of weather data. If not expanded, a single cell is needed to display a placeholder.
  3. The first cell should be a little larger than the others, as it displays a header. You don’t have to check the state of , because that header cell is shown as the first cell in either case.

Next you need to implement to configure the weather cells. Here are some detailed requirements:

  • The first cell should be of type , others should be .
  • Configure the weather summary cell with .
  • Configure four different weather detail cells with the following title and detail labels:
    1. “Sunrise” with
    2. “Sunset” with
    3. “High” with
    4. “Low” with

Give this cell setup a shot! The solution is just below.

Solution Inside: WeatherSectionController.cellForItem(at index:)SelectShow
func cellForItem(at index: Int) -> UICollectionViewCell { let cellClass: AnyClass = index == 0 ? WeatherSummaryCell.self : WeatherDetailCell.self let cell = collectionContext!.dequeueReusableCell(of: cellClass, for: self, at: index) if let cell = cell as? WeatherSummaryCell { cell.setExpanded(expanded) } else if let cell = cell as? WeatherDetailCell { let title: String, detail: String switch index { case 1: title = "SUNRISE" detail = weather.sunrise case 2: title = "SUNSET" detail = weather.sunset case 3: title = "HIGH" detail = "\(weather.high) C" case 4: title = "LOW" detail = "\(weather.low) C" default: title = "n/a" detail = "n/a" } cell.titleLabel.text = title cell.detailLabel.text = detail } return cell }

The last thing that you need to do is toggle the section and update the cells when tapped. Add the last required method in the extension:

func didSelectItem(at index: Int) { expanded = !expanded collectionContext?.reload(self) }

reloads the entire section. You can use this whenever the contents or number of cells changes in the section controller. Since you toggle the expansion with , this will add or remove cells based on the flag.

Return to FeedViewController.swift, and add the following near the top of , with the other properties:

let wxScanner = WxScanner()

is the model object for weather conditions.

Next, update in the extension so that it looks like the following:

// 1 var items: [IGListDiffable] = [wxScanner.currentWeather] items += loader.entries as [IGListDiffable] items += pathfinder.messages as [IGListDiffable] // 2 return items.sorted(by: { (left: Any, right: Any) -> Bool in if let left = left as? DateSortable, let right = right as? DateSortable { return left.date > right.date } return false })

You’ve updated the data source method to include . Here are details on what this does:

  1. Adds the to the items array.
  2. All the data conforms to the protocol, so this sorts it using that. This ensures data appears chronologically.

Finally, update to appear as follows:

if object is Message { return MessageSectionController() } else if object is Weather { return WeatherSectionController() } else { return JournalSectionController() }

This now returns a when a object appears.

Build and run again. You should see the new weather object at the top. Try tapping on the section to expand and contract it!

Performing Updates

JPL is ecstatic about your progress! While you were working, the director of NASA coordinated a rescue operation for the astronaut, requiring him to launch and intercept with another ship! It’s going to be a complicated launch, so he will have to liftoff at precisely the right time.

JPL engineering extended the messaging module with realtime chat and are asking you to integrate it.

Open FeedViewController.swift and add the following lines to the end of :

pathfinder.delegate = self pathfinder.connect()

The module is all patched up with realtime support. All you need to do is connect to the unit and respond to delegate events.

Add the following extension to the bottom of the file:

extension FeedViewController: PathfinderDelegate { func pathfinderDidUpdateMessages(pathfinder: Pathfinder) { adapter.performUpdates(animated: true) } }

now conforms to . The single method tells the to ask its data source for new objects and then update the UI. This handles objects that are deleted, updated, moved, or inserted.

Build and run to see the captain’s messages updating! All you had to do was add one single method for IGListKit to figure out what has changed in the data source and animate the changes when new data arrives.

All you need to do now is transmit the latest build to the astronaut and he’ll be coming home. A job well done!

Where To Go From here?

You can download the finished project here.

Aside from bringing a stranded astronaut home, you’ve learned a lot about the basic features of IGListKit: section controllers, adapters, and how to bring them all together. There are other important features in IGListKit like supplementary views and display events.

You can read and watch more about the origin of IGListKit at Instagram from a talk published by Realm. This talk covers a lot of the common problems that apps see as they get bigger.

If you’re interested in helping contribute to IGListKit, the team set up starter-task tags on Github for an easy way to get started.

Team

Each tutorial at www.raywenderlich.com is created by a team of dedicated developers so that it meets our high quality standards. The team members who worked on this tutorial are:

    Showing data in a gridview is a beautiful and space-saving solution for graphical data (e.g movies, books, pictures etc). It has been popular long before Apple introduced UICollectionView in iOS 6 – a powerful and highly customisable way to show gridviews in iOS.

    Before iOS 6 there were many ways to create a grid, including usage of UITableViews, UIScrollViews and custom open-source components. However, none of solutions was as powerful and as easy to use like UICollectionView.

    This tutorial will cover a basic usage scenario of UICollectionView. It will use the default layout that is called UICollectionViewFlowLayout. For most apps it is sufficient. The next tutorial will show, how to create custom layouts.

    CollectionView Components

    CollectionView implementation is separated between different Objects:

    • UICollectionView defines a visible area for its cells. It subclasses UIScrollView and therefore inherits all UIScrollView options like contentOffset or scrollEnabled.
    • UICollectionReusableView – All UICollectionView children must be subclasses of UICollectionReusableView. UICollectionReusableView provides basic view recycling mechanism to improve performance for big data sets. Usually it is not used directly for content items, but it is used for footer and header views.
    • UICollectionViewCell is a specific type of UICollectionReusableView for content items.
    • UICollectionViewLayout defines a frame for each cell and computes the total contentSize. UICollectionView highly depends on UICollectionViewLayout in determining cell locations and the total scrollable area.
    • UICollectionViewFlowLayout is the built-in layout that subclasses UICollectionViewLayout and is used to implement simple grids. The layout is highly customisable.

    The demo app

    We are going to build a gridview with some beautiful nature pictures. It can be used as a category view for a gallery or a photo app.

     

    Complete code

    You can find the complete code here (tested with Xcode 8.1, iOS 10.1):

     

    Getting started

    Open Xcode and create a new project by choosing the Single View Application template. Choose iPad under “Devices”. Choose whether Swift or Objective-C on the screen. This tutorial covers both Swift and Objective-C.

    Now let’s design the main user interface. Open Main.storyboard that should already have a single ViewController. Open the Object Library and find the UICollectionView object.

    Drag the UICollectionView to the ViewController’s view. Setup autolayout constraints to fill the superview with a small top offset (25px), so the collectionview does not overlap with a statusbar.

    It is also possible to use UICollectionViewController, but in most cases it is smarter to use just UICollectionView. If you wish to use UICollectionViewController, just replace the ViewController with UICollectionViewController in the Main.storyboard and add a new corresponding subclass of UICollectionViewController. All other steps should be similar.

    Now open the Attributes Inspector of the UICollectionView. Here you can see multiple options including layout, scroll direction and accessories. For static data it is possible to set the exact number of items and design all items in the Interface Builder. We will design in the Interface Builder only one cell, so items count can be set to 1. Chose “Flow” for the layout option, because we will use a built-in UICollectionViewFlowLayout for this tutorial. The important part is to mark the “Section header” option under Accessories, so the collectionview will have a header view.

    After those modifications the collectionview should have two subviews: a UICollectionReusableView and a UICollectionViewCell.

    Let’s now design the headerview. Open the Object Library and pick the UILabel object. Drag it to the header view (UICollectionReusableView). Change the font as you like and add constraints to center the label inside the headerview.

    Select the collectionview and change cell size to 300×300 px. This value will be overridden in code; we’ll make it bigger just for convenience. If cell sizes must be static, put here real sizes.

    Drag the UIImageView from the Object Library to UICollectionViewCell. Add appropriate autolayout constraints (fill superview with a small inset of 10 px on all sides).

    Adding classes

    For content cells and the headerview we’ll use corresponding subclasses.

    Add a new class “GalleryItemCommentView”, which extends “UICollectionReusableView”. It will also have an IBOutlet for UILabel.

    Objective-C:

    Swift:

    Also add a class for content cells. Name it “GalleryItemCollectionViewCell”. It should subclass UICollectionViewCell.

    Objective-C:

    Swift:

    Let’s also add some convenience implementation to the GalleryItemCollectionViewCell class, so that we can update reusable cells easier:

    Objective-C:

    Swift:

    As you see, it also has an IBOutlet for UIImageView. The method “setGalleryItem:” just sets the image.

    And here is the implementation for “GalleryItem”. It’s a simple model object that contains a single gallery image.

    Objective-C:

    Swift:

    Finalizing user interface

    Go back to the Storyboard and make some final changes. Select the headerview and set both its class and identifier to “GalleryItemCommentView”. Correspondingly, change the class and identifier of UICollectionViewCell to “GalleryItemCollectionViewCell”.

    Connect UILabel from the headerview and UIImageView from the cell to their corresponding IBOutlets.

    Add a UICollectionView outlet to the ViewController and connect it in the storyboard.

    Objective-C:

    Swift:

    Finally, add UICollectionViewDataSource and UICollectionViewDelegate protocols declarations to the ViewController. In the storyboard connect UICollectionView’s dataSource and delegate with the ViewController.

    Objective-C:

    Swift:

    <UICollectionViewDataSource, UICollectionViewDelegate>

    We are almost done. We only need to create some data objects and implement UICollectionViewDataSource/UICollectionViewDelegate protocols.

    Creating data objects is straightforward:

    1. Add some pictures to assets. You can download pictures for this demo project HERE.

    2. Add a new plist file. Name it items.plist. It will contain a list of all gallery items.

    3. Declare array for galleryItems in the ViewController:

    Objective-C:

    Swift:

    4.Read gallery items from the plist file and create corresponding model items:

    Objective-C:

    Swift:

    Call initGalleryItems in viewDidLoad and reload the collectionview afterwards.

    Objective-C:

    Swift:

    UICollectionViewDataSource

    The next step is to implement UICollectionViewDataSource.

    numberOfSectionsInCollectionView: is an optional method to return number of sections, which is useless to implement in terms of this demo project, but might be important for real projects:

    Objective-C:

    Swift:

    It is 1 by default, but if you need multiple sections, it should be implemented.

    Then add a required method collectionView:numberOfItemsInSection: to return number of items in section:

    Objective-C:

    Swift:

    The total number of gallery model items is returned here.

    To create cells implement cellForItemAtIndexPath:

    Objective-C:

    Swift:

    Because we designed our cell in the storyboard and changed both its identifier and class, the dequeueReusableCellWithReuseIdentifier: will return the correct class.

    To use a separate xib for a cell, UICollectionView has a handy method registerClass:forCellWithReuseIdentifier:. It should be implemented before calling dequeueReusableCellWithReuseIdentifier:.

    There’s a similar method for supplementary views. Supplementary views are usually used to implement the header and the footer view.

    We’ll implement only the header view using collectionView:viewForSupplementaryElementOfKind:atIndexPath: method:

    Objective-C:

    Swift:

    UICollectionViewDelegate

    To track selection of cells, use UICollectionViewDelegate. It has many options, including deselecting, highlighting, unhighlighting etc. Obviously, the most interesting is the cell selection:

    Objective-C:

    Swift:

    Our demo app will just show an alert when an item is selected.

    The last step is to dynamically change cell sizes and insets. Using a constant height or width might sometimes be not enough. UICollectionViewFlowLayout has multiple options that can also be changed dynamically by implementing UICollectionViewDelegateFlowLayout.

    Objective-C:

    Swift:

    Here we change dynamically some layout options, so our gridview will look nice in both portrait and landscape modes.

    The collectionview will redraw its children during the orientation change without any extra action. Thus, you don’t need to call extra reloadData during the orientation change. UICollectionViewFlowLayout will automatically change spacing between cells and cell sizes.

    Everything looks as expected:

    Complete code

    You can find the complete code here (tested with Xcode 8.1, iOS 10.1):

     

    Tags:gridview, ios, UICollectionView, UICollectionViewCell, UICollectionViewFlowLayout, UICollectionViewLayout

    One thought on “Uicollectionview Section Index Titles For Essays

    Leave a comment

    L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati *