Skip to content

Commit

Permalink
Update documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
davidask committed Aug 21, 2018
1 parent 15f8324 commit 134afbb
Show file tree
Hide file tree
Showing 33 changed files with 131 additions and 87 deletions.
4 changes: 2 additions & 2 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ excluded:
- Example

file_length:
warning: 800
error: 1000
warning: 1000
error: 1200

identifier_name:
max_length: 50
Expand Down
6 changes: 4 additions & 2 deletions Example/StateViewControllerExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -366,14 +366,15 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = StateViewControllerExample/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.formbound.StateViewControllerExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
TARGETED_DEVICE_FAMILY = 1;
};
name = Debug;
};
Expand All @@ -385,14 +386,15 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = StateViewControllerExample/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.formbound.StateViewControllerExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
TARGETED_DEVICE_FAMILY = 1;
};
name = Release;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ class ActivityIndicatorViewController: UIViewController {

@IBOutlet var activityIndicator: UIActivityIndicatorView!

@IBOutlet var activityIndicatorBackground: UIView!

override func viewDidLoad() {
super.viewDidLoad()
activityIndicatorBackground.layer.cornerRadius = 10
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
Expand All @@ -37,25 +43,29 @@ extension ActivityIndicatorViewController: StateViewControllerTransitioning {
if isAppearing {
view.alpha = 0
activityIndicator.transform = CGAffineTransform.identity.scaledBy(x: 3, y: 3)
activityIndicatorBackground.transform = CGAffineTransform.identity.scaledBy(x: 0.5, y: 0.5)
}
}

func stateTransitionDidEnd(isAppearing: Bool) {
view.alpha = 1
activityIndicator.transform = .identity
activityIndicatorBackground.transform = .identity
}

func animateAlongsideStateTransition(isAppearing: Bool) {
if isAppearing {
view.alpha = 1
activityIndicator.transform = .identity
activityIndicatorBackground.transform = .identity
} else {
view.alpha = 0
activityIndicator.transform = CGAffineTransform.identity.scaledBy(x: 0.5, y: 0.5)
activityIndicatorBackground.transform = CGAffineTransform.identity.scaledBy(x: 1.25, y: 1.25)
}
}

func stateTransitionDelay(isAppearing: Bool) -> TimeInterval {
return isAppearing ? 0 : 0.5
return isAppearing ? 0 : 0.25
}
}
23 changes: 18 additions & 5 deletions Example/StateViewControllerExample/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,32 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="syB-XM-5Fz">
<rect key="frame" x="169" y="315" width="37" height="37"/>
</activityIndicatorView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RDM-Bn-wL7">
<rect key="frame" x="149" y="304.5" width="77" height="77"/>
<subviews>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="syB-XM-5Fz">
<rect key="frame" x="29" y="29" width="20" height="20"/>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="syB-XM-5Fz" firstAttribute="centerX" secondItem="RDM-Bn-wL7" secondAttribute="centerX" id="71Y-ja-vcg"/>
<constraint firstAttribute="width" constant="77" id="GIb-4G-DXt"/>
<constraint firstAttribute="height" constant="77" id="Zfv-E0-qjg"/>
<constraint firstItem="syB-XM-5Fz" firstAttribute="centerY" secondItem="RDM-Bn-wL7" secondAttribute="centerY" id="zM6-bQ-noC"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="0.09892837703" green="0.130219996" blue="0.16634854669999999" alpha="0.77081549657534243" colorSpace="custom" customColorSpace="displayP3"/>
<constraints>
<constraint firstItem="syB-XM-5Fz" firstAttribute="centerY" secondItem="iWw-Nq-NbT" secondAttribute="centerY" id="eHp-l1-wbl"/>
<constraint firstItem="syB-XM-5Fz" firstAttribute="centerX" secondItem="iWw-Nq-NbT" secondAttribute="centerX" id="kGl-u0-i2i"/>
<constraint firstItem="RDM-Bn-wL7" firstAttribute="centerX" secondItem="1yS-p3-bkJ" secondAttribute="centerX" id="rQj-Q0-e9Y"/>
<constraint firstItem="syB-XM-5Fz" firstAttribute="centerY" secondItem="1yS-p3-bkJ" secondAttribute="centerY" id="u0J-YH-iTo"/>
</constraints>
<viewLayoutGuide key="safeArea" id="1yS-p3-bkJ"/>
</view>
<connections>
<outlet property="activityIndicator" destination="syB-XM-5Fz" id="DJn-L0-T2R"/>
<outlet property="activityIndicatorBackground" destination="RDM-Bn-wL7" id="BbT-75-VlB"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="8wb-4Y-cBo" userLabel="First Responder" sceneMemberID="firstResponder"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ class ListStateViewController: StateViewController<ListStateViewControllerState>
}

lazy private var tableViewController: TableViewController = {
// swiftlint:disable force_cast
let storyboard = UIStoryboard(name: "Main", bundle: .main)
return storyboard.instantiateViewController(withIdentifier: "tableViewController") as! TableViewController
// swiftlint:enable force_cast
}()

override func loadAppearanceState() -> ListStateViewControllerState {
Expand Down
Binary file added Images/example_gif.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@
When creating rich stateful view controllers, a single view controller class is often tasked with managing the appearance of many other views, controls, and other user interface elements based on a state. That state, in turn, is often inferred from multiple properties that need to be synchronized to correctly represent a single state. Usually the end result is known as the *Massive View Controller* problem, often solved by deviating from the [MVC](https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html) pattern used and endorsed heavily by Apple. While other patterns, such as [MVVM](https://en.wikipedia.org/wiki/Model–view–viewmodel) or [MVP](https://en.wikipedia.org/wiki/Model–view–presenter), can solve your issues, going with the grain rather than against makes interacting with UIKit a whole lot easier. *This repository houses one dependency-free class, called `StateViewController`, which is tasked with solving this issue.*

## Overview
StateViewController is a container view controller that presents one or more view controllers for any given state that you define, such as `loading`, `list`, or `editing`. It manages the appearance cycles of each content view controller, making sure that the view lifecycle of the content view controllers are intact and in order, notifying you about state transitions and which content view controllers are about to appear or disappear from the view hierarchy. This allos you to compose multiple view controllers and re-use them throughout the app. The state view controller also provides extensive support for animating the transition between states.
`StateViewController` is a container view controller that presents one or more view controllers for any given state that you define, such as `loading`, `list`, or `editing`. It manages the appearance cycles of each content view controller, making sure that the view lifecycle of the content view controllers are intact and in order, notifying you about state transitions and which content view controllers are about to appear or disappear from the view hierarchy. This allos you to compose multiple view controllers and re-use them throughout the app. The state view controller also provides extensive support for animating the transition between states.

## Typical usecase
The state view controller helps you manage child view controllers representing different states. In the example application included in this project the state view controller switches between two view controllers. Firstly, it displays and animates the transition of an activity indicator view controller while a network call is being performed. Once the network call is successfully completed it transitions into a state displaying a table view with the loaded content.


<p>
<img src="./Images/example_gif.gif" width="300" />
</p>

## Documentation

Expand Down
22 changes: 7 additions & 15 deletions Sources/StateViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public extension Notification.Name {
/// The default `StateViewControllerTransitionCoordinator` used, if `stateTransitionCoordinator(for:)` returns nil
/// or if a view content view controller of `StateViewController` does not conform to
/// `StateViewControllerTransitioning`.
public var defaultStateTransitioningCoordinator: StateViewControllerTransitionCoordinator?
public var defaultStateTransitionCoordinator: StateViewControllerTransitionCoordinator?

/// A container view controller that manages the appearance of one or more child view controller for any given state.
///
Expand Down Expand Up @@ -418,7 +418,7 @@ open class StateViewController<State: Equatable>: UIViewController {
/// Returns an optional `StateViewControllerTransitionCoordinator`, used to animate transitions between
/// states.
///
/// If the provided view controller conforms to `StateViewControllerTransitioning´, and this method returns
/// If the provided view controller conforms to `StateViewControllerTransitioning`, and this method returns
/// non-nil, the returned `StateViewControllerTransitionCoordinator` is used to animate the state transition
/// of the provided view controller.
///
Expand Down Expand Up @@ -614,7 +614,7 @@ fileprivate extension StateViewController {
} else if let cast = cast {
cast.stateTransitionWillBegin(isAppearing: isAppearing)
} else {
defaultStateTransitioningCoordinator?.stateTransitionWillBegin(
defaultStateTransitionCoordinator?.stateTransitionWillBegin(
viewController: viewController,
isAppearing: isAppearing
)
Expand All @@ -628,7 +628,7 @@ fileprivate extension StateViewController {
} else if let cast = cast {
cast.animateAlongsideStateTransition(isAppearing: isAppearing)
} else {
defaultStateTransitioningCoordinator?.animateAlongsideStateTransition(
defaultStateTransitionCoordinator?.animateAlongsideStateTransition(
of: viewController,
isAppearing: isAppearing
)
Expand All @@ -642,7 +642,7 @@ fileprivate extension StateViewController {
} else {
duration = cast?.stateTransitionDuration(
isAppearing: isAppearing
) ?? defaultStateTransitioningCoordinator?.stateTransitionDuration(
) ?? defaultStateTransitionCoordinator?.stateTransitionDuration(
for: viewController,
isAppearing: isAppearing
) ?? 0
Expand All @@ -655,7 +655,7 @@ fileprivate extension StateViewController {
} else {
delay = cast?.stateTransitionDelay(
isAppearing: isAppearing
) ?? defaultStateTransitioningCoordinator?.stateTransitionDelay(
) ?? defaultStateTransitionCoordinator?.stateTransitionDelay(
for: viewController,
isAppearing: isAppearing
) ?? 0
Expand All @@ -675,7 +675,7 @@ fileprivate extension StateViewController {
} else if let cast = cast {
cast.stateTransitionDidEnd(isAppearing: isAppearing)
} else {
defaultStateTransitioningCoordinator?.stateTransitionDidEnd(
defaultStateTransitionCoordinator?.stateTransitionDidEnd(
viewController: viewController,
isAppearing: isAppearing
)
Expand All @@ -698,14 +698,6 @@ fileprivate extension StateViewController {
}
}
}

private func animateStateTransition(
for viewController: UIViewController,
isAppearing: Bool,
coordinator: StateViewControllerTransitionCoordinator?,
completion: () -> Void) {

}
}

fileprivate extension StateViewController {
Expand Down
2 changes: 1 addition & 1 deletion StateViewController.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
shellScript = "";
};
/* End PBXShellScriptBuildPhase section */

Expand Down
6 changes: 3 additions & 3 deletions docs/Classes.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
<a class="nav-group-name-link" href="Global Variables.html">Global Variables</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="Global Variables.html#/s:19StateViewController07defaultA24TransitioningCoordinatorAA0abc10TransitionF0_pSgvp">defaultStateTransitioningCoordinator</a>
<a class="nav-group-task-link" href="Global Variables.html#/s:19StateViewController07defaultA21TransitionCoordinatorAA0abceF0_pSgvp">defaultStateTransitionCoordinator</a>
</li>
</ul>
</li>
Expand Down Expand Up @@ -203,7 +203,7 @@ <h2 id='animating-state-transitions' class='heading'>Animating state transitions
<p>By default, no animations are performed between states. To enable animations, you have three options:</p>

<ul>
<li>Set <code><a href="Global Variables.html#/s:19StateViewController07defaultA24TransitioningCoordinatorAA0abc10TransitionF0_pSgvp">defaultStateTransitioningCoordinator</a></code></li>
<li>Set <code>defaultStateTransitioningCoordinator</code></li>
<li>Override <code>stateTransitionCoordinator(for:)</code> in your <code>StateViewController</code> subclasses</li>
<li>Conform view controllers contained in <code>StateViewController</code> to <code><a href="Protocols/StateViewControllerTransitioning.html">StateViewControllerTransitioning</a></code>.</li>
</ul>
Expand Down Expand Up @@ -232,7 +232,7 @@ <h4>Declaration</h4>
</article>
</div>
<section class="footer">
<p>&copy; 2018 <a class="link" href="" target="_blank" rel="external">David Ask, Formbound AB</a>. All rights reserved. (Last updated: 2018-08-16)</p>
<p>&copy; 2018 <a class="link" href="" target="_blank" rel="external">David Ask, Formbound AB</a>. All rights reserved. (Last updated: 2018-08-21)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.9.3</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
Expand Down
10 changes: 5 additions & 5 deletions docs/Classes/StateViewController.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
<a class="nav-group-name-link" href="../Global Variables.html">Global Variables</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a class="nav-group-task-link" href="../Global Variables.html#/s:19StateViewController07defaultA24TransitioningCoordinatorAA0abc10TransitionF0_pSgvp">defaultStateTransitioningCoordinator</a>
<a class="nav-group-task-link" href="../Global Variables.html#/s:19StateViewController07defaultA21TransitionCoordinatorAA0abceF0_pSgvp">defaultStateTransitionCoordinator</a>
</li>
</ul>
</li>
Expand Down Expand Up @@ -187,7 +187,7 @@ <h2 id='animating-state-transitions' class='heading'>Animating state transitions
<p>By default, no animations are performed between states. To enable animations, you have three options:</p>

<ul>
<li>Set <code><a href="../Global Variables.html#/s:19StateViewController07defaultA24TransitioningCoordinatorAA0abc10TransitionF0_pSgvp">defaultStateTransitioningCoordinator</a></code></li>
<li>Set <code>defaultStateTransitioningCoordinator</code></li>
<li>Override <code>stateTransitionCoordinator(for:)</code> in your <code>StateViewController</code> subclasses</li>
<li>Conform view controllers contained in <code>StateViewController</code> to <code><a href="../Protocols/StateViewControllerTransitioning.html">StateViewControllerTransitioning</a></code>.</li>
</ul>
Expand Down Expand Up @@ -960,8 +960,8 @@ <h3 class="section-name">Animation</h3>
<p>Returns an optional <code><a href="../Protocols/StateViewControllerTransitionCoordinator.html">StateViewControllerTransitionCoordinator</a></code>, used to animate transitions between
states.</p>

<p>If the provided view controller conforms to <code>StateViewControllerTransitioning´, and this method returns
non-nil, the returned</code>StateViewControllerTransitionCoordinator` is used to animate the state transition
<p>If the provided view controller conforms to <code><a href="../Protocols/StateViewControllerTransitioning.html">StateViewControllerTransitioning</a></code>, and this method returns
non-nil, the returned <code><a href="../Protocols/StateViewControllerTransitionCoordinator.html">StateViewControllerTransitionCoordinator</a></code> is used to animate the state transition
of the provided view controller.</p>

</div>
Expand Down Expand Up @@ -1011,7 +1011,7 @@ <h4>Return Value</h4>
</article>
</div>
<section class="footer">
<p>&copy; 2018 <a class="link" href="" target="_blank" rel="external">David Ask, Formbound AB</a>. All rights reserved. (Last updated: 2018-08-16)</p>
<p>&copy; 2018 <a class="link" href="" target="_blank" rel="external">David Ask, Formbound AB</a>. All rights reserved. (Last updated: 2018-08-21)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.9.3</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</body>
Expand Down
Loading

0 comments on commit 134afbb

Please sign in to comment.