1

Learning iOS and trying to figure out the best way to share a "component" across multiple screens. I'm using programmatic layout and no storyboards so that may be making this more difficult than it should be.

I have a UIImageView paint palette chooser with a corresponding selection history UICollectionView of previously chosen colors that is used across many different screens. These are data source driven and also support some UI events like selection, scrolling, drag, etc. All of these interactions bubble up to the view controller for handling along with everything else on this screen. This makes it hard to re-use since the component is not self-contained but instead spread across some views with UI handling all flowing through the controller. How would I go about getting this thing self-contained so that I can just drop it into multiple screens without duplicating code?

Dark Castle
  • 1,289
  • 2
  • 9
  • 20

1 Answers1

2

Without seeing your exact code, I would suggest embedding your controller as a child controller of another view controller.

Example from the documentation:

- (void) displayContentController: (UIViewController*) content {
   [self addChildViewController:content];
   content.view.frame = [self frameForContentController];
   [self.view addSubview:self.currentClientView];
   [content didMoveToParentViewController:self];
}

Here's a Swift approach that you can drop in to your codebase. It extends UIViewController, so in your view controller's viewDidLoad, you can just call embed(myFancyNewChildController, withFrame: view.frame):

extension UIViewController {
    func embed(childViewController: UIViewController, withFrame frame: CGRect) {
        addChildViewController(childViewController)
        childViewController.view.frame = frame
        view.addSubview(childViewController.view)
        childViewController.didMove(toParentViewController: self)
    }
}

In this way, you can take your view controller and reuse it elsewhere by embedding it in another view controller of your choosing. In other words, all those moving parts get encapsulated into an entire controller which you can reuse elsewhere. As in the example above, you can also adjust the frame of the child controller accordingly.

For sake of simplicity, you can think of it as the view.addSubview(mySubview) method, but with an entire view controller.

Friendly King
  • 2,396
  • 1
  • 23
  • 40
  • This worked great. My only question is if it is necessary to adjust sub-controller sizes using frames? I tried to get this to work by setting autolayout constraints on the sub-controller views. Basically like ```paletteController.view.topAnchor.constraint(equalTo: coloringPageScrollView.bottomAnchor, constant: 10).isActive = true``` I could understand having to use frames so that the controllers are "bound" to a certain area on the page but it seems like autolayout would be the more modern approach? – Dark Castle Jan 09 '18 at 18:50
  • @DarkCastle Yes, using autolayout is typically the preferred / most modern approach. The only time I'd probably advise against using it is when laying out views inside tableView/collectionView cells (i.e., content that gets scrolled). It can be less performant than manual frame setting (see here: https://stackoverflow.com/questions/16949248/uitableviewcell-bad-performance-with-autolayout). – Friendly King Jan 09 '18 at 21:52