Coder Social home page Coder Social logo

swift-collectionview-catpuzzle-part2-nyc-web-career-010719's Introduction

Cat Pic Puzzle - Collection Views

snapshot

Objectives

  1. Build a picture game using a collection view controller
  2. Become familiar with data handling, view layout, and subclassing reusable views
  3. Determine the game winning sequence to trigger a segue and modally present another view controller

Part 2

Be sure to download and use the project files from this repo, as opposed to your files from Part 1.

1. Add Supplementary Views to the Collection View

Each section of a collection view has the option of including supplementary views (header and/or footer) of type UICollectionReusableView.

  • Add two variable properties on the CollectionViewController class:
  • var headerReusableView: HeaderReusableView!
  • var footerReusableView: FooterReusableView!
  • Add the following code snippet inside viewDidLoad() of the CollectionViewController class:
self.collectionView?.register(HeaderReusableView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "header")
self.collectionView?.register(FooterReusableView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "footer")
  • Add the following data source method below the existing data source methods in the CollectionViewController class:
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

   if kind == UICollectionElementKindSectionHeader {

       headerReusableView = (self.collectionView?.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "header", for: indexPath)) as! HeaderReusableView

       return headerReusableView

   } else {

       footerReusableView = (self.collectionView?.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "footer", for: indexPath)) as! FooterReusableView

       return footerReusableView
   }

}

There have been two subclasses created for you in this project that inherit from UICollectionReusableView, HeaderReusableView and FooterReusableView. These classes are being used programmatically in the project (i.e., not in storyboard). The method call used in viewDidLoad called register(_:forSupplementaryViewOfKind:withIdentifier:) registers the class with the collection view. The data source method, collectionView(_:viewForSupplementaryElementOfKind:at:), asks the data source object to provide the subclassed supplementary views to the collection view.

2. Configure the Layout

If you run the project you will not see any changes to the layout from part 1. Even though the header and footer views are included, they lack size. In fact, so far the only size information for the collection view is coming from default settings in interface builder. Let's change that.

  • Inside the CollectionViewController class, declare a method called configureLayout() that takes no arguments and has no return. Call this method inside viewDidLoad().
  • Add the following variable properties to the CollectionViewController class:
  • var sectionInsets: UIEdgeInsets!
  • var spacing: CGFloat!
  • var itemSize: CGSize!
  • var referenceSize: CGSize!
  • var numberOfRows: CGFloat!
  • var numberOfColumns: CGFloat!

The goal for the configureLayout() method is to set up all the dimensions for the various reusable views and spaces around them in the collection view. Once the dimensions are calculated, the values should be assigned to the appropriate properties you just declared.

IMPORTANT: This particular grid layout should fit all the reusable views (items(cells), header, footer) inside the dimensions of the screen. The header should be at the top, then the items should form a 3x4 grid, and then the footer should be at the bottom.

Before you begin calculating dimensions, you will need to update the CollectionViewController class to adhere to the UICollectionViewDelegateFlowLayout protocol. This will allow you to add the delegate methods necessary to provide the collection view with layout information.

  • Update your CollectionViewController class declaration to include adherence to UICollectionViewDelegateFlowLayout
  • Add the following methods to the CollectionViewController class:
  • collectionView(_:layout:minimumLineSpacingForSectionAt:) return spacing
  • collectionView(_:layout:minimumInteritemSpacingForSectionAt:) return spacing
  • collectionView(_:layout:insetForSectionAt:) return sectionInsets
  • collectionView(_:layout:sizeForItemAt:) return itemSize
  • collectionView(_:layout:referenceSizeForHeaderInSection:) return referenceSize
  • collectionView(_:layout:referenceSizeForFooterInSection:) return referenceSize

If you try to run the application, it will crash. Since the properties related to the layout were declared as implicitly unwrapped optionals, they don't have any values yet. Those properties must have values before the flow layout methods are called. That's what the configureLayout() method is for and why it's called in viewDidLoad(). Let's define the dimensions inside configureLayout().

  • Declare two variables for the width and height of the screen (Hint: UIScreen.main.bounds...).
  • Assign a value of 4 to numberOfRows.
  • Assign a value of 3 to numberOfColumns.
  • Assign a value of 2 to spacing (The spacing value will be used for section insets, minimum interitem spacing, and minimum line spacing).
  • Assign a value to sectionInsets using the UIEdgeInsets initializer (top, bottom, left, and right should all equal spacing).
  • Assign a value to referenceSize using the CGSize initializer (use the initializer that takes CGFloat). The width should be the width of the screen and the height should be 60.

The last layout dimension you need is the size for each item (cell) in the collection view. The item size is dependent on screen size, the numbers of rows/columns, and the space being used around each item (e.g., section insets, item spacing, line spacing, header/footer size).

  • Using variables and calculations as needed, determine the item width. You will need to divide the screen width by the number of columns. You will also need to subtract an equal portion of the total amount of space being taken up by left/right insets and item spacing.
  • Using variables and calculations as needed, determine the item height. You will need to divide the screen height by the number of rows. You will also need to subtract an equal portion of the total amount of space being taken up by top/bottom insets, line spacing, and header/footer height.
  • Assign a value to itemSize using the the CGSize initializer (use the initializer that takes CGFloat). Use the item width and height you calculated as your arguments.
  • Build and run the application. There should be 12 cat pictures taking up most of the screen with an equal amount of space on top and bottom for the header and the footer.

3. Provide Data to the Collection View

The collection view is currently using a static number, 12, for the number of items and the same picture for each cell. Let's provide an actual collection of data for the collection view. The assets folder has 12 picture slices to use in the collection view.

  • Declare and initialize a variable property called imageSlices that is an array of type UIImage.
  • Inside viewDidLoad() of the CollectionViewController class, use a for loop with a range to populate the imageSlices array with the images from the assets folder (images 1 through 12).
  • Update numberOfItems(inSection:) to return the count of the imageSlices array.
  • Update collectionView(_:cellForItemAt:) to grab an image from the imageSlices array instead of the same image it's currently using.
  • Build and run the application. You should see all the image slices in order making up a completed picture.

4. Add a Reordering Method to CollectionViewController

When you use a UICollectionViewController it's simple to add the option to reorder cells. By calling another data source method, the collection view will allow items to be reordered. There's animation built in too. You may notice it's difficult to move cells at first. Since this is a starter approach to reordering cells, there is no control over the gesture used on the cells. The cells require a long press before they begin to move.

  • Add the data source method collectionView(_:moveItemAt:to:) to the CollectionViewController class. Simply by overriding the method, the option to reorder cells is "turned on" therefore the body of the method can be left empty.
  • Build and run the application. You should be able to move cells to different locations within the collection view.

5. Randomize the imageSlices array

  • Write a function to randomize the imageSlices array after it's initially populated in viewDidLoad().
  • Build and run the application to see if your randomizer is working.

Advanced

There are a handful of other steps you can take to treat this even more like a game. Here's some hints to take this even further:

  • The FooterReusableView class has a timer and timer related functions. How could you incorporate those into the CollectionViewController class? Remember you have the footerReusableView property that is of type FooterReusableView. FooterReusableView has useful properties/methods like startTimer(), timer, and timerLabel.
  • How can you tell once a user has moved all the image slices back into order to complete the picture? collectionView(_:moveItemAt:to:) supplies you with the source index path and the destination index path when a cell is being moved. This information allows you the option to reorder the imageSlices array. Here's a code snippet you can add inside of collectionView(_:moveItemAt:to:) to help you out:
self.collectionView?.performBatchUpdates({

  // reorder the imageSlices array here


  }, completion: { completed in

      // 1. Check for winning scenario
      // 2. Invalidate the timer
      // 3. Perform segue with identifier "solvedSegue"

})
  • There is a segue set up in Main.storyboard to a second view controller called SolvedViewController. Use prepare(for:sender:) to segue to SolvedViewController. In the prepare for segue method, assign values to the properties of SolvedViewController named image and time. image should be the cats image in the assets folder. time should be the value of footerReusableView.timerLabel.text (the current time at the moment the puzzle was solved).

swift-collectionview-catpuzzle-part2-nyc-web-career-010719's People

Contributors

ianrahman avatar joelconnects avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.