From 766ca5183ada6797ebd770c2dd4380728cf6887f Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Mon, 27 Nov 2017 01:17:50 -0500 Subject: [PATCH] Working on View Controller transition --- Sources/Cacao/UIEventEnvironment.swift | 4 +- Sources/Cacao/UIView.swift | 66 ++++++++++++++ Sources/Cacao/UIViewController.swift | 98 +++++++++++++++++++-- Sources/Cacao/UIWheelEvent.swift | 1 + Sources/CacaoDemo/TableViewController.swift | 2 +- 5 files changed, 161 insertions(+), 10 deletions(-) diff --git a/Sources/Cacao/UIEventEnvironment.swift b/Sources/Cacao/UIEventEnvironment.swift index 13af80e..e8e60ff 100644 --- a/Sources/Cacao/UIEventEnvironment.swift +++ b/Sources/Cacao/UIEventEnvironment.swift @@ -167,9 +167,7 @@ internal final class UIEventEnvironment { case let .mouseWheel(translation): let event = UIWheelEvent(timestamp: timestamp, translation: translation) - - - + return event default: diff --git a/Sources/Cacao/UIView.swift b/Sources/Cacao/UIView.swift index cb94e94..abc7fea 100644 --- a/Sources/Cacao/UIView.swift +++ b/Sources/Cacao/UIView.swift @@ -352,19 +352,65 @@ open class UIView: UIResponder { @inline(__always) private func addSubview(_ view: UIView, _ body: (inout [UIView], UIView) -> ()) { + let oldWindow = view.window + let newWindow = self.window + + // remove from previous superview if view.superview !== self { view.removeFromSuperview() } + // store subview in array body(&subviews, view) + view.willMove(toSuperview: self) + + // set super view weak reference view.superview = self + // inform view of change + if oldWindow?.screen !== newWindow?.screen { + didMoveToScreen() + } + view.didMoveToSuperview() didAddSubview(view) + // force redraw setNeedsDisplay() } + private func willMove(fromWindow: UIWindow?, toWindow: UIWindow?) { + + guard fromWindow !== toWindow + else { return } + + if isFirstResponder { + let _ = resignFirstResponder() + } + + willMove(toWindow: toWindow) + + subviews.forEach { $0.willMove(fromWindow: fromWindow, toWindow: toWindow) } + + viewController?.beginAppearanceTransition(toWindow != nil, animated: false) + } + + private func didMove(fromWindow: UIWindow?, toWindow: UIWindow?) { + + guard fromWindow !== toWindow + else { return } + + + } + + private func didMoveToScreen() { + + //self.contentScaleFactor = self.window.screen.scale + self.setNeedsDisplay() + + self.subviews.forEach { $0.didMoveToScreen() } + } + /// Moves the specified subview so that it appears on top of its siblings. /// /// This method moves the specified view to the end of the array of views in the subviews property. @@ -626,6 +672,25 @@ open class UIView: UIResponder { open func draw(_ rect: CGRect) { /* implemented by subclasses */ } + /// The scale factor applied to the view. + /// + /// The scale factor determines how content in the view is mapped from the logical coordinate space + /// (measured in points) to the device coordinate space (measured in pixels). + /// This value is typically either 1.0 or 2.0. Higher scale factors indicate that each point in + /// the view is represented by more than one pixel in the underlying layer. + /// For example, if the scale factor is 2.0 and the view frame size is 50 x 50 points, + /// the size of the bitmap used to present that content is 100 x 100 pixels. + /// + /// The default value for this property is the scale factor associated with the screen currently displaying the view. + /// + /// In general, you should not need to modify the value in this property. + /// However, if your application draws using OpenGL ES, you may want to change + /// the scale factor to trade image quality for rendering performance. + public final var contentScaleFactor: CGFloat { + + return self.window?.screen.scale ?? UIScreen.main.scale + } + /// The backing rendering node / texture. /// /// Cacao's equivalent of `UIView.layer` / `CALayer`. @@ -889,6 +954,7 @@ open class UIView: UIResponder { /// Asks the view if the gesture recognizer should be allowed to continue tracking touch events. open func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + return true } diff --git a/Sources/Cacao/UIViewController.swift b/Sources/Cacao/UIViewController.swift index 471b1c6..a6a73e7 100644 --- a/Sources/Cacao/UIViewController.swift +++ b/Sources/Cacao/UIViewController.swift @@ -5,12 +5,7 @@ // Created by Alsey Coleman Miller on 6/7/17. // -import class Foundation.NSCoder -import class Foundation.Bundle -import struct Foundation.CGFloat -import struct Foundation.CGPoint -import struct Foundation.CGSize -import struct Foundation.CGRect +import Foundation import Silica open class UIViewController: UIResponder { @@ -127,6 +122,16 @@ open class UIViewController: UIResponder { open func viewDidAppear(_ animated: Bool) { + } + + open func viewWillDisappear(_ animated: Bool) { + + + } + + open func viewDidDisappear(_ animated: Bool) { + + } // MARK: - Configuring the View’s Layout Behavior @@ -161,6 +166,87 @@ open class UIViewController: UIResponder { parent?.childViewControllers.remove(at: index) } + /// Transitions between two of the view controller'€™s child view controllers. + /// + /// This method adds the second view controller'€™s view to the view hierarchy and + /// then performs the animations defined in your animations block. + /// After the animation completes, it removes the first view controller'€™s view from the view hierarchy. + /// This method is only intended to be called by an implementation of a custom container view controller. + /// If you override this method, you must call super in your implementation. + public func transition(from fromViewController: UIViewController, + to toViewController: UIViewController, + duration: TimeInterval, + options: UIViewAnimationOptions = [], + animations: (() -> Void)?, + completion: ((Bool) -> Void)? = nil) { + + let animated = duration > 0 + fromViewController.beginAppearanceTransition(false, animated: animated) + toViewController.beginAppearanceTransition(true, animated: animated) + + // run animations + + self.view.addSubview(toViewController.view) + fromViewController.view?.removeFromSuperview() + + } + + /// Returns a Boolean value indicating whether appearance methods are forwarded to child view controllers. + /// + /// - Returns: true if appearance methods are forwarded or false if they are not. + /// + /// This method is called to determine whether to automatically forward appearance-related containment + /// callbacks to child view controllers. + /// The default implementation returns true. Subclasses of the `UIViewController` class that implement containment + /// logic may override this method to control how these methods are forwarded. + /// If you override this method and return false, you are responsible for telling the child when its + /// views are going to appear or disappear. + /// You do this by calling the child view controller'€™s `beginAppearanceTransition(_:animated:)` + /// and `endAppearanceTransition()` methods. + public var shouldAutomaticallyForwardAppearanceMethods: Bool { + + return true + } + + /// Tells a child controller its appearance is about to change. + /// + /// If you are implementing a custom container controller, + /// use this method to tell the child that its views are about to appear or disappear. + public func beginAppearanceTransition(_ isAppearing: Bool, + animated: Bool) { + + if shouldAutomaticallyForwardAppearanceMethods { + + childViewControllers + .filter { $0.isViewLoaded && $0.view.isDescendant(of: self.view) } + .forEach { $0.beginAppearanceTransition(isAppearing, animated: animated) } + } + + if isAppearing { + + let _ = self.view + viewWillAppear(animated) + + } else { + + viewWillDisappear(animated) + } + } + + /// Tells a child controller its appearance has changed. + /// + /// If you are implementing a custom container controller, + /// use this method to tell the child that the view transition is complete. + public func endAppearanceTransition() { + + if shouldAutomaticallyForwardAppearanceMethods { + + childViewControllers.forEach { $0.endAppearanceTransition() } + } + + //if isview + } + // MARK: - Responding to Containment Events // MARK: - Getting Other Related View Controllers diff --git a/Sources/Cacao/UIWheelEvent.swift b/Sources/Cacao/UIWheelEvent.swift index b144679..b755e79 100644 --- a/Sources/Cacao/UIWheelEvent.swift +++ b/Sources/Cacao/UIWheelEvent.swift @@ -23,6 +23,7 @@ public final class UIWheelEvent: UIEvent { extension UIWheelEvent: UIResponderEvent { + @inline(__always) func sendEvent(to responder: UIResponder) { responder.wheelChanged(with: self) diff --git a/Sources/CacaoDemo/TableViewController.swift b/Sources/CacaoDemo/TableViewController.swift index e74c21d..46416d1 100644 --- a/Sources/CacaoDemo/TableViewController.swift +++ b/Sources/CacaoDemo/TableViewController.swift @@ -23,7 +23,7 @@ final class TableViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() - + tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier) #if os(iOS)