// // ToolbarViewController.swift // SBrowser // // Created by James Magahern on 7/23/20. // import UIKit class ToolbarButtonView: UIView { private var buttonPadding = CGFloat(24.0) private var buttonViews: [UIView] = [] func addButtonView(_ button: UIView) { buttonViews.append(button) addSubview(button) setNeedsLayout() } override func sizeThatFits(_ size: CGSize) -> CGSize { let width: CGFloat = buttonViews.reduce(0.0) { (result, button) -> CGFloat in return result + button.sizeThatFits(size).width + buttonPadding } return CGSize(width: width, height: size.height) } override func layoutSubviews() { var buttonRect = CGRect(origin: .zero, size: CGSize(width: 0, height: bounds.height)) buttonRect.origin.x = layoutMargins.left for button in buttonViews { let buttonSize = button.sizeThatFits(bounds.size) buttonRect.size = CGSize(width: buttonSize.width, height: bounds.height) button.frame = buttonRect buttonRect.origin.x += buttonRect.width + buttonPadding } } } class ToolbarView: UIView { var urlBar: URLBar? { didSet { containerView.addSubview(urlBar!) } } var cancelButtonVisible: Bool = false { didSet { layoutSubviews() } } let containerView = UIView(frame: .zero) let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .systemThickMaterial)) let buttonsView = ToolbarButtonView(frame: .zero) let cancelButton = UIButton(type: .system) convenience init() { self.init(frame: .zero) addSubview(backgroundView) addSubview(containerView) containerView.addSubview(buttonsView) cancelButton.setTitle("Cancel", for: .normal) containerView.addSubview(cancelButton) } override func sizeThatFits(_ size: CGSize) -> CGSize { return CGSize(width: size.width, height: 44.0) } override func layoutSubviews() { super.layoutSubviews() backgroundView.frame = bounds var containerBounds = bounds containerBounds.size.height -= safeAreaInsets.bottom containerView.frame = containerBounds containerView.frame = containerView.frame.insetBy(dx: 8.0, dy: 4.0) // Cancel button let urlBarPadding: CGFloat = 8.0 let cancelButtonSize = cancelButton.sizeThatFits(containerView.bounds.size) cancelButton.frame = CGRect(origin: CGPoint(x: (urlBar?.frame.maxX ?? 0) + urlBarPadding, y: 0), size: CGSize(width: cancelButtonSize.width, height: containerView.bounds.height)) // Toolbar buttons let toolbarSize = buttonsView.sizeThatFits(containerView.bounds.size) buttonsView.frame = CGRect(origin: CGPoint(x: (urlBar?.frame.maxX ?? 0) + urlBarPadding, y: 0), size: toolbarSize) var avoidingSize: CGSize = .zero if cancelButtonVisible { cancelButton.alpha = 1.0 buttonsView.alpha = 0.0 avoidingSize = cancelButtonSize } else { cancelButton.alpha = 0.0 buttonsView.alpha = 1.0 avoidingSize = toolbarSize } if let urlBar = urlBar { urlBar.frame = CGRect(origin: .zero, size: CGSize(width: containerView.bounds.width - avoidingSize.width - urlBarPadding, height: containerView.bounds.height)) } } } class ToolbarViewController: UIViewController { let urlBar = URLBar() let toolbarView = ToolbarView() let scriptControllerIconView = ScriptControllerIconView() let shareButton = UIButton(frame: .zero) let darkModeButton = UIButton(frame: .zero) init() { super.init(nibName: nil, bundle: nil) toolbarView.urlBar = urlBar darkModeButton.setImage(UIImage(systemName: "moon.circle"), for: .normal) toolbarView.buttonsView.addButtonView(darkModeButton) shareButton.setImage(UIImage(systemName: "square.and.arrow.up"), for: .normal) toolbarView.buttonsView.addButtonView(shareButton) toolbarView.buttonsView.addButtonView(scriptControllerIconView) let toolbarAnimationDuration: TimeInterval = 0.3 urlBar.textField.addAction(.init(handler: { _ in UIView.animate(withDuration: toolbarAnimationDuration) { self.toolbarView.cancelButtonVisible = self.urlBar.textField.isFirstResponder } }), for: [ .editingDidBegin, .editingDidEnd ]) toolbarView.cancelButton.addAction(.init(handler: { action in self.urlBar.textField.resignFirstResponder() }), for: .touchUpInside) } override func loadView() { self.view = toolbarView } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }