// // DropShawdowViewController.swift // VDSSample // // Created by Matt Bruce on 6/13/23. // import Foundation import UIKit import VDS import VDSTokens import Combine class DropShadowViewController: BaseViewController { var viewPaddingRange = Slider() var viewRadiusRange = Slider() var viewSpacerRange = Slider() //shadow 1 var showShadow = Toggle() var opacityRange = Slider() var radiusRange = Slider() var offsetXRange = Slider() var offsetYRange = Slider() //shadow 2 var showShadow2 = Toggle() var opacityRange2 = Slider() var radiusRange2 = Slider() var offsetXRange2 = Slider() var offsetYRange2 = Slider() var viewSize: CGFloat = 100.0 var componentWrapper: UIView! var componentConstraints: NSLayoutConstraint.Container! var secondView = View() var thirdView = View() lazy var backgroundColorPickerSelectorView = { PickerSelectorView(title: "paletteWhite", picker: self.picker, items: UIColor.VDSColor.allCases) }() lazy var dropShadowLightColorPickerSelectorView = { PickerSelectorView(title: "", picker: self.picker, items: UIColor.VDSColor.allCases) }() lazy var dropShadowDarkColorPickerSelectorView = { PickerSelectorView(title: "", picker: self.picker, items: UIColor.VDSColor.allCases) }() lazy var dropShadow2LightColorPickerSelectorView = { PickerSelectorView(title: "", picker: self.picker, items: UIColor.VDSColor.allCases) }() lazy var dropShadow2DarkColorPickerSelectorView = { PickerSelectorView(title: "", picker: self.picker, items: UIColor.VDSColor.allCases) }() lazy var viewLightColorPickerSelectorView = { PickerSelectorView(title: "", picker: self.picker, items: UIColor.VDSColor.allCases) }() lazy var viewDarkColorPickerSelectorView = { PickerSelectorView(title: "", picker: self.picker, items: UIColor.VDSColor.allCases) }() var spacer: CGFloat = 0 { didSet { spacings.forEach{ $0.constant = spacer } } } var viewPadding: CGFloat = 0 { didSet { componentConstraints.topConstraint?.constant = viewPadding componentConstraints.leadingConstraint?.constant = viewPadding componentConstraints.trailingConstraint?.constant = -viewPadding componentConstraints.bottomConstraint?.constant = -viewPadding } } var spacings = [NSLayoutConstraint]() override func viewDidLoad() { super.viewDidLoad() let label1 = Label().with { $0.text = "View 1"; $0.textAlignment = .center} let label2 = Label().with { $0.text = "View 2"; $0.textAlignment = .center} let label3 = Label().with { $0.text = "View 3"; $0.textAlignment = .center} component.addSubview(label1) label1.pinToSuperView() secondView.addSubview(label2) label2.pinToSuperView() thirdView.addSubview(label3) label3.pinToSuperView() let wrapper = UIView.makeWrapperWithConstraints(for: component, isTrailing: false) componentWrapper = wrapper.view componentConstraints = wrapper.container contentTopView.addSubview(secondView) contentTopView.addSubview(thirdView) contentTopView.addSubview(componentWrapper) component.width(viewSize).height(viewSize) secondView.width(viewSize).height(viewSize) thirdView.width(viewSize).height(viewSize) componentWrapper.pinTop().pinLeading() secondView.pinTop() thirdView.pinLeading().pinBottom() secondView.pinTrailingLessThanOrEqualTo(contentTopView.trailingAnchor) secondView.pinBottomLessThanOrEqualTo(contentTopView.bottomAnchor) thirdView.pinTrailingLessThanOrEqualTo(contentTopView.trailingAnchor) spacings.append(thirdView.pinTop(anchor: componentWrapper.bottomAnchor)!) spacings.append(secondView.pinLeading(anchor: componentWrapper.trailingAnchor)!) viewPadding = 10 spacer = 10 component.setNeedsUpdate() setupPicker() setupModel() updateView() } override func showDebug(show: Bool) { super.showDebug(show: show) component.debugBorder(show: false) componentWrapper.debugBorder(show: show, color: .green) secondView.debugBorder(show: show, color: .green) thirdView.debugBorder(show: show, color: .green) } override func setupForm(){ super.setupForm() formStackView.title = "Screen Settings" addFormRow(label: "Background Color", view: backgroundColorPickerSelectorView) addFormRow(label: "Space Between 1,2,3", view: viewSpacerRange) let form1 = FormSection() form1.title = "View 1 Settings" form1.addFormRow(label: "All ", view: viewPaddingRange) form1.addFormRow(label: "Padding", view: viewPaddingRange) form1.addFormRow(label: "Corner Radius", view: viewRadiusRange) form1.addFormRow(label: "Light", view: viewLightColorPickerSelectorView) form1.addFormRow(label: "Dark", view: viewDarkColorPickerSelectorView) let form2 = FormSection() form2.title = "View 1 Shadow Settings" form2.addFormRow(label: "Show", view: .makeWrapper(for: showShadow)) form2.addFormRow(label: "Shawdow Light", view: dropShadowLightColorPickerSelectorView) form2.addFormRow(label: "Shawdow Dark", view: dropShadowDarkColorPickerSelectorView) form2.addFormRow(label: "Radius (Blur)", view: radiusRange) form2.addFormRow(label: "Width (OffSet X)", view: offsetXRange) form2.addFormRow(label: "Height (Offset Y)", view: offsetYRange) form2.addFormRow(label: "Opacity", view: opacityRange) let form3 = FormSection() form3.title = "View 1 Shadow 2 Settings" form3.addFormRow(label: "Show", view: .makeWrapper(for: showShadow2)) form3.addFormRow(label: "Shawdow Light", view: dropShadow2LightColorPickerSelectorView) form3.addFormRow(label: "Shawdow Dark", view: dropShadow2DarkColorPickerSelectorView) form3.addFormRow(label: "Radius (Blur)", view: radiusRange2) form3.addFormRow(label: "Width (OffSet X)", view: offsetXRange2) form3.addFormRow(label: "Height (Offset Y)", view: offsetYRange2) form3.addFormRow(label: "Opacity", view: opacityRange2) append(section: form1) append(section: form2) append(section: form3) //shadow1 showShadow.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in self?.component.showShadow = slider.isOn self?.updateView() }).store(in: &subscribers) opacityRange.maximumValue = 1.0 opacityRange.minimumValue = 0.0 opacityRange.value = 1.0 opacityRange.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in self?.component.opacityRange = CGFloat(slider.value) self?.updateView() }).store(in: &subscribers) radiusRange.maximumValue = 20.0 radiusRange.minimumValue = 0.0 radiusRange.value = 2.0 radiusRange.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in self?.component.radiusRange = CGFloat(slider.value) self?.updateView() }).store(in: &subscribers) offsetXRange.maximumValue = 20 offsetXRange.minimumValue = -20 offsetXRange.value = 2.0 offsetXRange.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in self?.component.offsetXRange = CGFloat(slider.value) self?.updateView() }).store(in: &subscribers) offsetYRange.maximumValue = 20 offsetYRange.minimumValue = -20 offsetYRange.value = 2.0 offsetYRange.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in self?.component.offsetYRange = CGFloat(slider.value) self?.updateView() }).store(in: &subscribers) //shadow2 showShadow2.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in self?.component.showShadow2 = slider.isOn self?.updateView() }).store(in: &subscribers) opacityRange2.maximumValue = 1.0 opacityRange2.minimumValue = 0.0 opacityRange2.value = 1.0 opacityRange2.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in self?.component.opacityRange2 = CGFloat(slider.value) self?.updateView() }).store(in: &subscribers) radiusRange2.maximumValue = 20.0 radiusRange2.minimumValue = 0.0 radiusRange2.value = 2.0 radiusRange2.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in self?.component.radiusRange2 = CGFloat(slider.value) self?.updateView() }).store(in: &subscribers) offsetXRange2.maximumValue = 20 offsetXRange2.minimumValue = -20 offsetXRange2.value = 2.0 offsetXRange2.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in self?.component.offsetXRange2 = CGFloat(slider.value) self?.updateView() }).store(in: &subscribers) offsetYRange2.maximumValue = 20 offsetYRange2.minimumValue = -20 offsetYRange2.value = 2.0 offsetYRange2.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in self?.component.offsetYRange2 = CGFloat(slider.value) self?.updateView() }).store(in: &subscribers) //view viewPaddingRange.maximumValue = 50.0 viewPaddingRange.minimumValue = 0.0 viewPaddingRange.value = 2.0 viewPaddingRange.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in self?.viewPadding = CGFloat(slider.value) self?.updateView() }).store(in: &subscribers) viewRadiusRange.maximumValue = Float(viewSize / 2) viewRadiusRange.minimumValue = 0 viewRadiusRange.value = 8.0 viewRadiusRange.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in self?.component.viewRadiusRange = CGFloat(slider.value) self?.updateView() }).store(in: &subscribers) viewSpacerRange.maximumValue = 50 viewSpacerRange.minimumValue = 0 viewSpacerRange.value = 10.0 viewSpacerRange.publisher(for: .valueChanged).sink(receiveValue: { [weak self] slider in self?.spacer = CGFloat(slider.value) }).store(in: &subscribers) dropShadowLightColorPickerSelectorView.text = component.shadowLightColor.rawValue dropShadowDarkColorPickerSelectorView.text = component.shadowDarkColor.rawValue dropShadow2LightColorPickerSelectorView.text = component.shadowLightColor2.rawValue dropShadow2DarkColorPickerSelectorView.text = component.shadowDarkColor2.rawValue viewLightColorPickerSelectorView.text = component.viewLightColor.rawValue viewDarkColorPickerSelectorView.text = component.viewDarkColor.rawValue showShadow.isOn = component.showShadow showShadow2.isOn = component.showShadow2 } func setupModel() { //setup UI } override func updateView() { secondView.backgroundColor = .red thirdView.backgroundColor = .purple } func setupPicker(){ backgroundColorPickerSelectorView.onPickerDidSelect = { [weak self] item in self?.contentTopView.backgroundColor = item.uiColor self?.updateView() } dropShadowDarkColorPickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.shadowDarkColor = item } dropShadowLightColorPickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.shadowLightColor = item } dropShadow2DarkColorPickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.shadowDarkColor2 = item } dropShadow2LightColorPickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.shadowLightColor2 = item } viewLightColorPickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.viewLightColor = item } viewDarkColorPickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.viewDarkColor = item } } } public class ShadowView: View { public var viewLightColor: UIColor.VDSColor = .paletteGray65 { didSet { setNeedsUpdate() }} public var viewDarkColor: UIColor.VDSColor = .backgroundPrimaryLight { didSet { setNeedsUpdate() }} public var viewRadiusRange: CGFloat = 8.0 { didSet { setNeedsUpdate() }} public var showShadow: Bool = true { didSet { setNeedsUpdate() }} public var opacityRange: CGFloat = 1.0 { didSet { setNeedsUpdate() }} public var offsetXRange: CGFloat = 2.0 { didSet { setNeedsUpdate() }} public var offsetYRange: CGFloat = 2.0 { didSet { setNeedsUpdate() }} public var radiusRange: CGFloat = 2.0 { didSet { setNeedsUpdate() }} public var shadowLightColor: UIColor.VDSColor = .backgroundPrimaryDark { didSet { setNeedsUpdate() }} public var shadowDarkColor: UIColor.VDSColor = .backgroundPrimaryLight { didSet { setNeedsUpdate() }} public var showShadow2: Bool = false { didSet { setNeedsUpdate() }} public var opacityRange2: CGFloat = 1.0 { didSet { setNeedsUpdate() }} public var offsetXRange2: CGFloat = 2.0 { didSet { setNeedsUpdate() }} public var offsetYRange2: CGFloat = 2.0 { didSet { setNeedsUpdate() }} public var radiusRange2: CGFloat = 2.0 { didSet { setNeedsUpdate() }} public var shadowLightColor2: UIColor.VDSColor = .backgroundPrimaryDark { didSet { setNeedsUpdate() }} public var shadowDarkColor2: UIColor.VDSColor = .backgroundPrimaryLight { didSet { setNeedsUpdate() }} public override func setup() { super.setup() width(constant: 100) height(constant: 100) } public override func updateView() { super.updateView() let viewColor = SurfaceColorConfiguration(viewLightColor.uiColor, viewDarkColor.uiColor).getColor(surface) backgroundColor = viewColor setNeedsLayout() layoutIfNeeded() } public override var backgroundColor: UIColor? { didSet { print("backgroundColor: \(backgroundColor?.hexString ?? "None")") } } public override func layoutSubviews() { super.layoutSubviews() layer.cornerRadius = CGFloat(viewRadiusRange) let dropshadowColor = SurfaceColorConfiguration(shadowLightColor.uiColor, shadowDarkColor.uiColor).getColor(surface) let dropshadowColor2 = SurfaceColorConfiguration(shadowLightColor2.uiColor, shadowDarkColor2.uiColor).getColor(surface) var shadowConfigs = [DropShadowConfiguration]() // Update shadow layers frames to match the view's bounds if showShadow { let shadow1Config = VDS.DropShadowConfiguration().with { $0.shadowRadiusConfiguration = .init(viewRadiusRange, .zero) $0.shadowColorConfiguration = SurfaceColorConfiguration(dropshadowColor, dropshadowColor).eraseToAnyColorable() $0.shadowOpacityConfiguration = .init(opacityRange, .zero) $0.shadowOffsetConfiguration = .init(.init(width: offsetXRange, height: offsetYRange), .zero) $0.shadowRadiusConfiguration = .init(radiusRange, .zero) } shadowConfigs.append(shadow1Config) } if showShadow2 { let shadow2Config = VDS.DropShadowConfiguration().with { $0.shadowRadiusConfiguration = .init(viewRadiusRange, .zero) $0.shadowColorConfiguration = SurfaceColorConfiguration(dropshadowColor2, dropshadowColor2).eraseToAnyColorable() $0.shadowOpacityConfiguration = .init(opacityRange2, .zero) $0.shadowOffsetConfiguration = .init(.init(width: offsetXRange2, height: offsetYRange2), .zero) $0.shadowRadiusConfiguration = .init(radiusRange2, .zero) } shadowConfigs.append(shadow2Config) } if shadowConfigs.count > 0 { addDropShadows(shadowConfigs) } else { removeDropShadows() } } }