mvm_core_ui/MVMCoreUI/Containers/Container.swift

240 lines
9.5 KiB
Swift

//
// Container.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 12/11/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
public protocol ContainerModelProtocol {
var horizontalAlignment: UIStackView.Alignment? { get set }
var verticalAlignment: UIStackView.Alignment? { get set }
var useHorizontalMargins: Bool? { get set }
var useVerticalMargins: Bool? { get set }
}
public class ContainerHelper: NSObject {
var leftConstraint: NSLayoutConstraint?
var topConstraint: NSLayoutConstraint?
var bottomConstraint: NSLayoutConstraint?
var rightConstraint: NSLayoutConstraint?
var alignCenterHorizontalConstraint: NSLayoutConstraint?
var alignCenterLeftConstraint: NSLayoutConstraint?
var alignCenterRightConstraint: NSLayoutConstraint?
var alignCenterVerticalConstraint: NSLayoutConstraint?
var alignCenterTopConstraint: NSLayoutConstraint?
var alignCenterBottomConstraint: NSLayoutConstraint?
var leftLowConstraint: NSLayoutConstraint?
var topLowConstraint: NSLayoutConstraint?
var bottomLowConstraint: NSLayoutConstraint?
var rightLowConstraint: NSLayoutConstraint?
func constrainView(_ view: UIView) {
guard let margins = view.superview?.layoutMarginsGuide else { return }
leftConstraint = view.leftAnchor.constraint(equalTo: margins.leftAnchor)
leftConstraint?.isActive = true
topConstraint = view.topAnchor.constraint(equalTo: margins.topAnchor)
topConstraint?.isActive = true
rightConstraint = margins.rightAnchor.constraint(equalTo: view.rightAnchor)
rightConstraint?.isActive = true
bottomConstraint = margins.bottomAnchor.constraint(equalTo: view.bottomAnchor)
bottomConstraint?.isActive = true
alignCenterHorizontalConstraint = view.centerXAnchor.constraint(equalTo: margins.centerXAnchor)
alignCenterLeftConstraint = view.leftAnchor.constraint(greaterThanOrEqualTo: margins.leftAnchor)
alignCenterRightConstraint = margins.rightAnchor.constraint(greaterThanOrEqualTo: view.rightAnchor)
alignCenterVerticalConstraint = view.centerYAnchor.constraint(equalTo: margins.centerYAnchor)
alignCenterTopConstraint = view.topAnchor.constraint(greaterThanOrEqualTo: margins.topAnchor)
alignCenterBottomConstraint = margins.bottomAnchor.constraint(greaterThanOrEqualTo: view.bottomAnchor)
leftLowConstraint = view.leftAnchor.constraint(equalTo: margins.leftAnchor)
leftLowConstraint?.priority = UILayoutPriority(rawValue: 200)
leftLowConstraint?.isActive = true
topLowConstraint = view.topAnchor.constraint(equalTo: margins.topAnchor)
topLowConstraint?.priority = UILayoutPriority(rawValue: 200)
topLowConstraint?.isActive = true
rightLowConstraint = margins.rightAnchor.constraint(equalTo: view.rightAnchor)
rightLowConstraint?.priority = UILayoutPriority(rawValue: 200)
rightLowConstraint?.isActive = true
bottomLowConstraint = margins.bottomAnchor.constraint(equalTo: view.bottomAnchor)
bottomLowConstraint?.priority = UILayoutPriority(rawValue: 200)
bottomLowConstraint?.isActive = true
setAccessibility(view)
}
func setAccessibility(_ view: UIView) {
guard let superView = view.superview else { return }
superView.isAccessibilityElement = false
if let elements = view.accessibilityElements {
superView.accessibilityElements = elements
} else {
superView.accessibilityElements = [view]
}
}
func alignHorizontal(_ alignment: UIStackView.Alignment) {
switch alignment {
case .center:
alignCenterHorizontalConstraint?.isActive = true
alignCenterLeftConstraint?.isActive = true
alignCenterRightConstraint?.isActive = true
leftConstraint?.isActive = false
rightConstraint?.isActive = false
case .leading:
alignCenterHorizontalConstraint?.isActive = false
alignCenterLeftConstraint?.isActive = false
alignCenterRightConstraint?.isActive = true
leftConstraint?.isActive = true
rightConstraint?.isActive = false
case .trailing:
alignCenterHorizontalConstraint?.isActive = false
alignCenterLeftConstraint?.isActive = true
alignCenterRightConstraint?.isActive = false
leftConstraint?.isActive = false
rightConstraint?.isActive = true
case .fill:
alignCenterHorizontalConstraint?.isActive = false
alignCenterLeftConstraint?.isActive = false
alignCenterRightConstraint?.isActive = false
leftConstraint?.isActive = true
rightConstraint?.isActive = true
default: break
}
}
func alignVertical(_ alignment: UIStackView.Alignment) {
switch alignment {
case .center:
alignCenterVerticalConstraint?.isActive = true
alignCenterTopConstraint?.isActive = true
alignCenterBottomConstraint?.isActive = true
topConstraint?.isActive = false
bottomConstraint?.isActive = false
case .leading:
alignCenterVerticalConstraint?.isActive = false
alignCenterTopConstraint?.isActive = false
alignCenterBottomConstraint?.isActive = true
topConstraint?.isActive = true
bottomConstraint?.isActive = false
case .trailing:
alignCenterVerticalConstraint?.isActive = false
alignCenterTopConstraint?.isActive = true
alignCenterBottomConstraint?.isActive = false
topConstraint?.isActive = false
bottomConstraint?.isActive = true
case .fill:
alignCenterVerticalConstraint?.isActive = false
alignCenterTopConstraint?.isActive = false
alignCenterBottomConstraint?.isActive = false
topConstraint?.isActive = true
bottomConstraint?.isActive = true
default: break
}
}
func set(with model: ContainerModelProtocol) {
if let horizontalAlignment = model.horizontalAlignment {
alignHorizontal(horizontalAlignment)
}
if let verticalAlignment = model.verticalAlignment {
alignVertical(verticalAlignment)
}
}
static func getAlignment(for string: String) -> UIStackView.Alignment? {
switch string {
case "leading":
return .leading
case "trailing":
return .trailing
case "center":
return .center
case "fill":
return .fill
default:
return nil
}
}
func set(with JSON: [AnyHashable: Any]?, for contained: UIView) {
if let horizontalAlignmentString = JSON?.optionalStringForKey("horizontalAlignment"), let alignment = ContainerHelper.getAlignment(for: horizontalAlignmentString) ?? (contained as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() {
alignHorizontal(alignment)
} else if let alignment = (contained as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() {
alignHorizontal(alignment)
}
if let verticalAlignmentString = JSON?.optionalStringForKey("verticalAlignment"), let alignment = ContainerHelper.getAlignment(for: verticalAlignmentString) ?? (contained as? MVMCoreUIViewConstrainingProtocol)?.verticalAlignment?() {
alignVertical(alignment)
} else if let alignment = (contained as? MVMCoreUIViewConstrainingProtocol)?.verticalAlignment?() {
alignVertical(alignment)
}
}
}
open class Container: View {
var containerModel: ContainerModelProtocol?
var view: UIView?
let containerHelper = ContainerHelper()
var topMarginPadding: CGFloat = 0
var bottomMarginPadding: CGFloat = 0
}
// MARK: - MVMCoreViewProtocol
public extension Container {
override func updateView(_ size: CGFloat) {
super.updateView(size)
(view as? MVMCoreViewProtocol)?.updateView(size)
MFStyler.setMarginsFor(self, size: size, defaultHorizontal: containerModel?.useHorizontalMargins ?? true, top: containerModel?.useHorizontalMargins ?? true ? topMarginPadding : 0, bottom: containerModel?.useHorizontalMargins ?? true ? bottomMarginPadding : 0)
}
/// Will be called only once.
override func setupView() {
super.setupView()
backgroundColor = .clear
}
func addAndContain(_ view: UIView) {
view.translatesAutoresizingMaskIntoConstraints = false
addSubview(view)
containerHelper.constrainView(view)
self.view = view
}
convenience init(andContain view: UIView) {
self.init()
addAndContain(view)
}
}
// MARK: - MVMCoreUIMoleculeViewProtocol
public extension Container {
override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
guard let view = view else { return }
containerHelper.set(with: json, for: view)
}
override func reset() {
super.reset()
(view as? MVMCoreUIMoleculeViewProtocol)?.reset?()
}
func setAsMolecule() {
(view as? MVMCoreUIMoleculeViewProtocol)?.setAsMolecule?()
}
}