A child view controller framework that makes setting up your parent controllers as easy as pie.

Related tags

UI Family
Overview

Family logo

CI Status Version Carthage Compatible codecov License Platform Swift

Description

Family Icon

Family is a child view controller framework that makes setting up your parent controllers as easy as pie. With a simple yet powerful public API, you can build complex layouts without losing maintainability, leaving you to focus on what matters: making your applications pop and your business logic shine.

This framework was built to make it easier to build and maintain parent controllers, also known as flow controllers. Using child view controllers can make your code more modular, flexible and testable. It addresses one of the biggest shortcomings of the vanilla approach: how do you get a continuous scrolling experience while keeping dequeuing intact?

This is where Family framework comes in. With the help of its layout algorithm, all your regular- and scroll views get stacked in the same linear vertical order you add them to the hierarchy. To achieve a continuous scrolling view, your child scroll views no longer scroll themselves, but get their new content offset passed to them by the parent scroll view, which the framework handles for you. The framework also modifies the views' frames on the fly, constraining the height to the window.

The story behind Family

If you are interested in the origin story behind Family, then you can read this Medium article.

Features

  • 🍩 Animation support.
  • 🀳🏻Continuous scrolling with multiple scroll views.
  • πŸ“ Margins between child view controllers.
  • πŸŒ€ Table view and collection view dequeuing.
  • 🍭 Supports custom spacing between views.
  • πŸ“± iOS support.
  • πŸ’» macOS support.
  • ?? tvOS support.

Supporting the project

If you want to support the development of this framework, you can do so by becoming a sponsor. ❀️

Usage

The new public API:

body(withDuration: 0) {
  add(detailViewController)
  .background(.view(backgroundView))
  .padding(.init(top: 20, left: 20, bottom: 20, right: 20))
  .margin(.init(top: 20, left: 0, bottom: 20, right: 0))
}

Add a regular child view controller:

let familyController = FamilyViewController()
let viewController = UIViewController()

familyController.addChild(viewController)

Add a child view controller constrained by height:

let familyController = FamilyViewController()
let viewController = UIViewController()

familyController.addChild(viewController, height: 175)

Add a child view controller with a custom view on the controller:

let familyController = FamilyViewController()
let customController = CustomViewController()

// This will add the scroll view of the custom controller
// instead of the controllers view.
familyController.addChild(customController, view: { $0.scrollView })

Move a view controller:

familyController.moveChild(customController, to: 1)

Perform batch updates (it is encouraged to use performBatchUpdates when updaing more than one view controller):

familyController.performBatchUpdates({ controller in
  controller.addChild(controller1)
  controller.addChild(controller2)
  controller.moveChild(controller2, to: 0)
  controller3.removeFromParent()
})

Adding animations

When adding animations, not that you have to give them a key.

let basicAnimation = CABasicAnimation()
basicAnimation.duration = 0.5
controller.view.layer.add(springAnimation, forKey: "Basic Animations")

let springAnimation = CASpringAnimation()
springAnimation.damping = 0.6
springAnimation.initialVelocity = 0.6
springAnimation.mass = 0.4
springAnimation.duration = 0.6
springAnimation.isRemovedOnCompletion = false
controller.view.layer.add(springAnimation, forKey: "Spring Animations")

Installation

Family is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'Family'

and then run

pod install

Family is also available through Carthage. To install just write into your Cartfile:

github "zenangst/Family"

and then run

carthage install

When it's finished, install the built framework (which can be found in the Carthage/Build folder) into your Xcode project.

Family can also be installed manually. Just download and drop Sources folders in your project.

Author

Christoffer Winterkvist, [email protected]

Contributing

We would love you to contribute to Family, check the CONTRIBUTING file for more info.

Credits

License

Family is available under the MIT license. See the LICENSE file for more info.

Comments
  • Add Swift Package Manager support

    Add Swift Package Manager support

    Hello I'm trying to give a little help regarding support of Swift Package Manager as I need it in one of my project :) This is a very simple implementation I just did and allowed me to use Family with SPM recently. I'm not sure if this is good enough but I think it is a good base to start with if it helps.

    Changes

    • Create target for shared code between macOS and mobile platforms (iOS & tvOS) named Family-Shared. This target is used by both macOS and mobile target.
    • Family-mobile encapsulate both tvOS and iOS frameworks.
    opened by zocario 22
  • Question: Is automatic height for children supported?

    Question: Is automatic height for children supported?

    Hello and thanks for this library :)

    We're trying to take advantage of child view controllers to split a view controller that is now really too complex. Here is how we want to organize it after refactoring (at the moment this is one UITableViewController subclass):

    image

    1. One view controller for the header
    2. One view controller for our list of items that are linked to core data using an NSFetchedResultsController
    3. A fixed view controller for a toolbar allowing to enter text and create content

    I've just started to play with your library and I encountered a problem : our header has a dynamic height, which is set automatically with auto layout constraints. I've succeed to set fixed height for this container using the height parameter of addChild but with only auto layout constraints I couldn't. Also I encountered a case where I could scroll in the tableview and the main scroll view wasn't scrolling..

    So I would like to know if this is supported to have height set using auto layout? Regarding https://github.com/zenangst/Family/issues/73 I have the feeling it's not.

    Regarding your experience in child view controller, is it a good pattern to split this controller in three view controllers in that way? Maybe it's just easier to use the table view header to add the header controller?

    I've included a sample project to quickly show the problem I'm having. Test family.zip

    Thanks for your help!

    question 
    opened by zocario 14
  • UICollectionView inside FamilyViewController has incorrect behavior.

    UICollectionView inside FamilyViewController has incorrect behavior.

    The view hierarchy is FamilyViewController --UICollectionView inside a UIViewController --UICollectionView inside a UIViewController

    They are added using addChild(viewController, view: { $0.collectionView })

    Each collectionView has 50 items retrieved from network with content size over the screen height. image The result is that the collectionView does not show all the items when scrolling down. The demo project is here https://github.com/superk589/FamilyDemo What's wrong in my implementation?

    bug 
    opened by superk589 11
  • UICollectionView's didSelectItem isn't called for UICollectionViewController

    UICollectionView's didSelectItem isn't called for UICollectionViewController

    Hello,

    I have a new issue related to the last fix made for UICollectionViewController (viewWillAppear not called). The did select item method isn't triggered in my UICollectionViewController subclass anymore after update to the last version of Family. Also the navigation bar doesn't update its large title to small title when scrolling (it works fine with only a table view).

    Steps to reproduce:

    1. Create a FamilyViewController containing a view controller subclassing UICollectionViewController
    2. Present the controller
    3. Override collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) in your UICollectionViewController subclass

    Whats happens:

    • The collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) method isn't called on the UICollectionViewController subclass.
    • The navigation bar doesn't update its large title while scrolling

    What should happens:

    • collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) should be called correctly.
    • The navigation bar update its large title while scrolling

    Sample: Test family collection view 2.zip

    bug 
    opened by zocario 10
  • Card interface (similar to Snapchat or Duolingo), Incorrect behavior on iPhone X-series

    Card interface (similar to Snapchat or Duolingo), Incorrect behavior on iPhone X-series

    Is it possible to use Family to create a card-like interface, similar to Snapchat or Duolingo with multiple rounded cards that scroll infinetely?

    image image

    So far I was able to achieve a very similar effect, but with some flaws using this code:

      func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        let family = FamilyViewController()
        family.view.backgroundColor = .white
        let vc1 = TableViewController1()
        let vc2 = TableViewController2()
    
        family.addChild(vc1)
        family.addChild(vc2)
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = family
        window?.makeKeyAndVisible()
    
        return true
      }
    

    The result looks like this: simulator screen shot - iphone xs - 2018-10-23 at 13 28 07

    So, the problem is really with the outer corners which should not be visible if there is some content further down (or up) the table.

    What would be ideal is to add some padding where the views could extend before being recycled.

    I.e. currently the tableviews are limited by the FamilyController's alignment rect, or at least, respects the top and bottom safe area insets. Because of that, the layout looks weird on the X-series phones.

    Having some parameter (i.e. margins to extend) would give an option to both achieve the card-like looks and fix the x-series bug.

    Video Description

    enhancement 
    opened by richardtop 10
  • Multiple UICollectionViews inside FamilyViewController will be jumpy when scrolling

    Multiple UICollectionViews inside FamilyViewController will be jumpy when scrolling

    ezgif-4-8878a7150142 This new issue only occurs on real devices. (The device above is iOS 12.4, iPhone X) When a collection view with more than one screen items followed by a new collection view with fewer items, the first collection view will be jumpy. Use demo code here(the newest commit): https://github.com/superk589/FamilyDemo

    bug 
    opened by superk589 9
  • Fix height not correctly resized when remove child

    Fix height not correctly resized when remove child

    Issue

    Hello,

    First, thanks for your framework we have complex ViewController in our app and this is really useful for us!

    I have an issue when I remove a view from the parent view controller. purgeRemovedViews() & scrollView.purgeWrapperViews() are not called so obviously the height is not correctly resize and a blank space is still visible.

    If you want to test the issue, please find this sample.

    Test no resize height.zip

    Fix

    The fix is pretty simple because all methods already exists. I just create a removeChild function (as we have for the addChild) to call this private methods purgeRemovedViews() & scrollView.purgeWrapperViews().

    opened by ThomasLeblond 8
  • UISelectionGrabberDot should not be wrapped by FamilyWrapperView

    UISelectionGrabberDot should not be wrapped by FamilyWrapperView

    I found this bug when embedding a UITextView inside a UITableViewCell, then in a FamilyViewController. UISelectionGrabberDot is a private type of UIKit, it represents the two pins on the two sides of the selected range. image

    familydemo

    This view is wrapped by FamilyWrapperView. And it causes some strange behavior such as an incorrect frame of the dot's first ancestor scroll view subclass, the UITextView.

    bug 
    opened by superk589 8
  • Question

    Question

    Hi, this is not an issue but more of a question of how to use your library. I have a view controller built in storyboard and it has multiple views that require their own controller. However, because I don't know how to set child view controller properly, I have one massive view controller managing three different views. I find this library very useful in terms of separating three views into separate view controllers and having a parent controller.

    1. Can I have FamilyViewController as subclass of my parent controller that is built in storyboard?
    2. For the views that I have setup in storyboard using constraints, is it possible for me to have each view have child view controller like, view1 = viewController1.view when I do add addChild(viewController1)?
    3. How does the memory allocation work, do all child and parent view controllers get deallocated as soon as the navigation controller gets dismissed since they are part of navigation controller stack?
    question 
    opened by h36ahmed 8
  • viewWillAppear isn't called on UICollectionViewController child

    viewWillAppear isn't called on UICollectionViewController child

    Hello,

    I have a new issue, this time when using an UICollectionViewController as child controller :)

    Steps to reproduce:

    1. Create a FamilyViewController containing a view controller subclassing UICollectionViewController
    2. Present the controller

    Whats happens: The viewWillAppear method isn't called on the UICollectionViewController subclass.

    What should happens: viewWillAppear should be called correctly.

    I've found a workaround by creating an UIViewController containing an UICollectionView, then it's working correctly.

    Sample: Test family collection view.zip

    bug 
    opened by zocario 6
  • Feature request: Allow collection view that can both scrolling vertically and horizontally

    Feature request: Allow collection view that can both scrolling vertically and horizontally

    I can hardly say this is a reasonable use case. But this is what I am dealing with. There is a collection view, like an excel table, which can scroll both vertically and horizontally, is inside a FamilyViewController. But with isDirectionalLockEnabled, it can only scroll at one direction at one time.

    Because FamilyScrollView has code lines below:

      func configureScrollView(_ scrollView: UIScrollView) {
        #if os(iOS)
        scrollView.scrollsToTop = false
        if let collectionView = scrollView as? UICollectionView,
          (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.scrollDirection == .horizontal {
          scrollView.isScrollEnabled = true
        } else {
          scrollView.isScrollEnabled = false
        }
        #else
        for scrollView in subviewsInLayoutOrder {
          scrollView.isScrollEnabled = scrollViewIsHorizontal(scrollView)
        }
        #endif
      }
    

    The "excel" collection view always has it's scrollView.isScrollEnabled on. It sometimes freezes the whole FamilyViewController vertically, when it fills the whole screen and can only scroll horizontally. The gesture can not pass to the container scroll view below.

    question 
    opened by superk589 6
  • Support for UIRefreshControl ?

    Support for UIRefreshControl ?

    Hello,

    We're having some weird issues when trying to add a UIRefreshControl on top of FamilyViewController. When pulling everything if fine. But whenever we're refreshing, the refresh control just disappears or is having a lot of UI issues.

    I can reproduce this in the demo app by enabling large title and setting up scrollView.refreshControl = UIRefreshControl()

    Note that it's the same if we're trying to use directly FamilyScrollView.

    Do you have any idea what could cause this?

    Thank you so much :)

    opened by Antoine4011 1
  • Introduce XcodeGen

    Introduce XcodeGen

    Instead of having a bundled Xcode project, I'd like to propose using XcodeGen to generate the project-based of a .yml file. This would reduce the occasional merge conflicts that can occur when multiple people are making PR's at the same time. Also, it would clean up PR's by not including Xcode project changes as they are invalid with XcodeGen in place.

    For more information about XcogeGen, check out their README

    • https://github.com/yonaskolb/XcodeGen
    good first issue 
    opened by zenangst 0
  • Improve README with algorithm information, best practices and examples

    Improve README with algorithm information, best practices and examples

    The README could use some updating to ensure that we both explain the underlying technical aspects of the framework, how the algorithm works, and some best practice information on how to best adapt the framework into your apps.

    Some example images of what could be built would be a big bonus here.

    good first issue 
    opened by zenangst 0
  • Experiment and see if Family can support SwiftUI

    Experiment and see if Family can support SwiftUI

    Family does one thing and it does it pretty great. It is to encapsulate scroll views (and other views) into one scrollable feed meanwhile ensuring that dequeuing stays intact for things like collection views and table views and that performance is still top-notch. This is normally kinda hard to achieve in UIKit, hence the framework's inception.

    The way forward, now that we are slowly transitioning into the world of SwiftUI, it would be interesting to see if this framework could be adapted to support the same kind of functionality in that landscape. SwiftUI does support multiple vertical stacks inside of a scroll view, but not with things like List which is harder to get working when they should be self-sizing.

    I propose that we do some experimentation here to see if there is a future for Family inside SwiftUI-land.

    question 
    opened by zenangst 0
  • Improve test coverage

    Improve test coverage

    We should consider rewriting the test suites for the different targets to ensure that we have all the most important parts of the framework covered. Now, tvOS is lagging a bit behind the other platforms.

    enhancement 
    opened by zenangst 0
Releases(2.2.3)
Owner
Christoffer Winterkvist
random hero at @finkoslo by day, cocoa vigilante by night, dad at dawn. my life is awesome. Previously @hyperoslo
Christoffer Winterkvist
iOS custom controller used in Jobandtalent app to present new view controllers as cards

CardStackController iOS custom controller used in the Jobandtalent app to present new view controllers as cards. This controller behaves very similar

jobandtalent 527 Dec 15, 2022
A controller that uses a UIStackView and view controller composition to display content in a list

StackViewController Overview StackViewController is a Swift framework that simplifies the process of building forms and other static content using UIS

Seed 867 Dec 27, 2022
Windless makes it easy to implement invisible layout loading view.

Windless Windless makes it easy to implement invisible layout loading view. Contents Requirements Installation Usage Looks Credits Communication Licen

ArLupin 940 Dec 22, 2022
An iOS Library that makes shadows management easy on UIView.

ShadowView is an iOS Shadow library that makes view's shadow implementation easy and sweet ?? ?? . Add simple shadows to add a gaussian blurred projec

Pierre 404 Dec 8, 2022
A UIControl subclass that makes it easy to create empty states.

AZEmptyState Making empty state simple. Screenshots Installation Cocoa Pods: pod 'AZEmptyState' Manual: Simply drag and drop the Sources folder to you

Antonio Zaitoun 88 Oct 2, 2022
A library, which adds the ability to hide navigation bar when view controller is pushed via hidesNavigationBarWhenPushed flag

HidesNavigationBarWhenPushed A library, which adds the ability to hide navigation bar when view controller is pushed via hidesNavigationBarWhenPushed

Danil Gontovnik 55 Oct 19, 2022
A set of UIKit helpers that simplify the usage of UIKit view's and controller's in SwiftUI.

A set of UIKit helpers that simplify the usage of UIKit view's and controller's in SwiftUI. Many of these helpers are useful even in a pure UIKit project.

SwiftUI+ 6 Oct 28, 2022
Page view controller with bounce effect

BouncyPageViewController Page view controller with bounce effect inspired by motion design by Stan Yakushevish. Quickstart Create a queue of UIViewCon

Bohdan Orlov 843 Oct 17, 2022
ElongationPreview is an elegant UI push-pop style view controller

ElongationPreview is an elegant UI push-pop style view controller

Ramotion 886 Dec 19, 2022
πŸ“– A simple, highly informative page view controller

TL;DR UIPageViewController done properly. ⭐️ Features Simplified data source management & enhanced delegation. Dynamically insert & remove pages. Infi

UI At Six 1.8k Dec 24, 2022
Provides an iOS view controller allowing a user to draw their signature with their finger in a realistic style.

Swift version now available! Mimicking pen-on-paper signatures with a touch screen presents a difficult set of challenges. The rate touch events are e

Uber Open Source 1.3k Jan 6, 2023
Meet Page View Controller for iOS by Cleveroad

While a standard page view allows you to navigate between pages by using simple gestures, our component goes further

Cleveroad 397 Aug 20, 2022
Confetti View lets you create a magnificent confetti view in your app

ConfettiView Confetti View lets you create a magnificent confetti view in your app. This was inspired by House Party app's login screen. Written in Sw

Or Ron 234 Nov 22, 2022
A drop-in universal library helps you to manage the navigation bar styles and makes transition animations smooth between different navigation bar styles

A drop-in universal library helps you to manage the navigation bar styles and makes transition animations smooth between different navigation bar styles while pushing or popping a view controller for all orientations. And you don't need to write any line of code for it, it all happens automatically.

Zhouqi Mo 3.3k Dec 21, 2022
AGCircularPicker is helpful component for creating a controller aimed to manage any calculated parameter

We are pleased to offer you our new free lightweight plugin named AGCircularPicker. AGCircularPicker is helpful for creating a controller aimed to man

Agilie Team 617 Dec 19, 2022
Highly customizable Action Sheet Controller with Assets Preview written in Swift

PPAssetsActionController Play with me ▢️ ?? If you want to play with me, just tap here and enjoy! ?? ?? Show me ?? Try me ?? The easiest way to try me

Pavel Pantus 72 Feb 4, 2022
Reel Search is a Swift UI controller that allows you to choose options from a list

REEL SEARCH Reel Search is a Swift UI controller that allows you to choose options from a list We specialize in the designing and coding of custom UI

Ramotion 2.5k Dec 21, 2022
A SwiftUI bottom-up controller, like in the Maps app. Drag to expand or minimize.

SwiftUI Drawer A SwiftUI bottom-up controller, like in the Maps app. Drag to expand or minimize. Contents Add the Package Basic Usage Examples Credits

Michael Verges 695 Jan 3, 2023