// // EKEntryView.swift // SwiftEntryKit // // Created by Daniel Huri on 4/15/18. // Copyright (c) 2018 huri000@gmail.com. All rights reserved. // import UIKit class EKEntryView: EKStyleView { struct Content { var viewController: UIViewController! var view: UIView! var attributes: EKAttributes init(viewController: UIViewController, attributes: EKAttributes) { self.viewController = viewController self.view = viewController.view self.attributes = attributes } init(view: UIView, attributes: EKAttributes) { self.view = view self.attributes = attributes } } // MARK: Props /** Background view */ private var backgroundView: EKBackgroundView! /** The content - contains the view, view controller, attributes */ var content: Content private lazy var contentView: UIView = { return UIView() }() var attributes: EKAttributes { return content.attributes } private lazy var contentContainerView: EKStyleView = { let contentContainerView = EKStyleView() self.addSubview(contentContainerView) contentContainerView.layoutToSuperview(axis: .vertically) contentContainerView.layoutToSuperview(axis: .horizontally) contentContainerView.clipsToBounds = true return contentContainerView }() // MARK: Setup init(newEntry content: Content) { self.content = content super.init(frame: UIScreen.main.bounds) setupContentView() applyDropShadow() applyBackgroundToContentView() applyFrameStyle() adjustInnerContentAppearanceIfNeeded() } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func layoutSubviews() { super.layoutSubviews() applyFrameStyle() } func transform(to view: UIView) { let previousView = content.view content.view = view view.layoutIfNeeded() let previousHeight = set(.height, of: frame.height, priority: .must) let nextHeight = set(.height, of: view.frame.height, priority: .defaultLow) SwiftEntryKit.layoutIfNeeded() UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: [.beginFromCurrentState, .layoutSubviews], animations: { previousHeight.priority = .defaultLow nextHeight.priority = .must previousView!.alpha = 0 SwiftEntryKit.layoutIfNeeded() }, completion: { (finished) in view.alpha = 0 previousView!.removeFromSuperview() self.removeConstraints([previousHeight, nextHeight]) self.setupContentView() UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: [.curveEaseOut], animations: { view.alpha = 1 }, completion: nil) }) } private func setupContentView() { contentView.addSubview(content.view) content.view.layoutToSuperview(axis: .horizontally) content.view.layoutToSuperview(axis: .vertically) contentContainerView.addSubview(contentView) contentView.fillSuperview() contentView.layoutToSuperview(axis: .vertically) contentView.layoutToSuperview(axis: .horizontally) } // Complementary logic for issue #117 private func adjustInnerContentAppearanceIfNeeded() { guard let view = content.view as? EntryAppearanceDescriptor else { return } view.bottomCornerRadius = attributes.roundCorners.cornerValues?.radius ?? 0 } // Apply round corners private func applyFrameStyle() { backgroundView.applyFrameStyle(roundCorners: attributes.roundCorners, border: attributes.border) } // Apply drop shadow private func applyDropShadow() { switch attributes.shadow { case .active(with: let value): applyDropShadow(withOffset: value.offset, opacity: value.opacity, radius: value.radius, color: value.color.color(for: traitCollection, mode: attributes.displayMode)) case .none: removeDropShadow() } } // Apply background private func applyBackgroundToContentView() { let attributes = content.attributes let backgroundView = EKBackgroundView() backgroundView.style = .init(background: attributes.entryBackground, displayMode: attributes.displayMode) switch attributes.positionConstraints.safeArea { case .empty(fillSafeArea: let fillSafeArea) where fillSafeArea: // Safe area filled with color insertSubview(backgroundView, at: 0) backgroundView.layoutToSuperview(axis: .horizontally) var topInset: CGFloat = 0 var bottomInset: CGFloat = 0 switch attributes.position { case .top: topInset = -EKWindowProvider.safeAreaInsets.top case .bottom, .center: bottomInset = EKWindowProvider.safeAreaInsets.bottom } backgroundView.layoutToSuperview(.top, offset: topInset) backgroundView.layoutToSuperview(.bottom, offset: bottomInset) default: // Float case or a Toast with unfilled safe area contentView.insertSubview(backgroundView, at: 0) backgroundView.fillSuperview() } self.backgroundView = backgroundView } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { applyDropShadow() } }