import Foundation import UIKit import AsyncDisplayKit public final class ToolbarNode: ASDisplayNode { private var theme: TabBarControllerTheme private let displaySeparator: Bool private let left: () -> Void private let right: () -> Void private let middle: () -> Void private let separatorNode: ASDisplayNode private let leftTitle: ImmediateTextNode private let leftButton: HighlightableButtonNode private let rightTitle: ImmediateTextNode private let rightButton: HighlightableButtonNode private let middleTitle: ImmediateTextNode private let middleButton: HighlightableButtonNode public init(theme: TabBarControllerTheme, displaySeparator: Bool = false, left: @escaping () -> Void, right: @escaping () -> Void, middle: @escaping () -> Void) { self.theme = theme self.displaySeparator = displaySeparator self.left = left self.right = right self.middle = middle self.separatorNode = ASDisplayNode() self.separatorNode.isLayerBacked = true self.leftTitle = ImmediateTextNode() self.leftTitle.displaysAsynchronously = false self.leftButton = HighlightableButtonNode() self.rightTitle = ImmediateTextNode() self.rightTitle.displaysAsynchronously = false self.rightButton = HighlightableButtonNode() self.middleTitle = ImmediateTextNode() self.middleTitle.displaysAsynchronously = false self.middleButton = HighlightableButtonNode() super.init() self.addSubnode(self.leftTitle) self.addSubnode(self.leftButton) self.addSubnode(self.rightTitle) self.addSubnode(self.rightButton) self.addSubnode(self.middleTitle) self.addSubnode(self.middleButton) if self.displaySeparator { self.addSubnode(self.separatorNode) } self.updateTheme(theme) self.leftButton.addTarget(self, action: #selector(self.leftPressed), forControlEvents: .touchUpInside) self.leftButton.highligthedChanged = { [weak self] highlighted in if let strongSelf = self { if highlighted { strongSelf.leftTitle.layer.removeAnimation(forKey: "opacity") strongSelf.leftTitle.alpha = 0.4 } else { strongSelf.leftTitle.alpha = 1.0 strongSelf.leftTitle.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) } } } self.rightButton.addTarget(self, action: #selector(self.rightPressed), forControlEvents: .touchUpInside) self.rightButton.highligthedChanged = { [weak self] highlighted in if let strongSelf = self { if highlighted { strongSelf.rightTitle.layer.removeAnimation(forKey: "opacity") strongSelf.rightTitle.alpha = 0.4 } else { strongSelf.rightTitle.alpha = 1.0 strongSelf.rightTitle.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) } } } self.middleButton.addTarget(self, action: #selector(self.middlePressed), forControlEvents: .touchUpInside) self.middleButton.highligthedChanged = { [weak self] highlighted in if let strongSelf = self { if highlighted { strongSelf.middleTitle.layer.removeAnimation(forKey: "opacity") strongSelf.middleTitle.alpha = 0.4 } else { strongSelf.middleTitle.alpha = 1.0 strongSelf.middleTitle.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) } } } } public func updateTheme(_ theme: TabBarControllerTheme) { self.separatorNode.backgroundColor = theme.tabBarSeparatorColor self.backgroundColor = theme.tabBarBackgroundColor } public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, toolbar: Toolbar, transition: ContainedViewLayoutTransition) { transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: UIScreenPixel))) let sideInset: CGFloat = 16.0 self.leftTitle.attributedText = NSAttributedString(string: toolbar.leftAction?.title ?? "", font: Font.regular(17.0), textColor: (toolbar.leftAction?.isEnabled ?? false) ? self.theme.tabBarSelectedTextColor : self.theme.tabBarTextColor) self.rightTitle.attributedText = NSAttributedString(string: toolbar.rightAction?.title ?? "", font: Font.regular(17.0), textColor: (toolbar.rightAction?.isEnabled ?? false) ? self.theme.tabBarSelectedTextColor : self.theme.tabBarTextColor) self.middleTitle.attributedText = NSAttributedString(string: toolbar.middleAction?.title ?? "", font: Font.regular(17.0), textColor: (toolbar.middleAction?.isEnabled ?? false) ? self.theme.tabBarSelectedTextColor : self.theme.tabBarTextColor) let leftSize = self.leftTitle.updateLayout(size) let rightSize = self.rightTitle.updateLayout(size) let middleSize = self.middleTitle.updateLayout(size) let leftFrame = CGRect(origin: CGPoint(x: leftInset + sideInset, y: floor((size.height - bottomInset - leftSize.height) / 2.0)), size: leftSize) let rightFrame = CGRect(origin: CGPoint(x: size.width - rightInset - sideInset - rightSize.width, y: floor((size.height - bottomInset - rightSize.height) / 2.0)), size: rightSize) let middleFrame = CGRect(origin: CGPoint(x: floor((size.width - middleSize.width) / 2.0), y: floor((size.height - bottomInset - middleSize.height) / 2.0)), size: middleSize) if leftFrame.size == self.leftTitle.frame.size { transition.updateFrame(node: self.leftTitle, frame: leftFrame) } else { self.leftTitle.frame = leftFrame } if rightFrame.size == self.rightTitle.frame.size { transition.updateFrame(node: self.rightTitle, frame: rightFrame) } else { self.rightTitle.frame = rightFrame } if middleFrame.size == self.middleTitle.frame.size { transition.updateFrame(node: self.middleTitle, frame: middleFrame) } else { self.middleTitle.frame = middleFrame } self.leftButton.isEnabled = toolbar.leftAction?.isEnabled ?? false self.rightButton.isEnabled = toolbar.rightAction?.isEnabled ?? false self.middleButton.isEnabled = toolbar.middleAction?.isEnabled ?? false self.leftButton.frame = CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: leftSize.width + sideInset * 2.0, height: size.height - bottomInset)) self.rightButton.frame = CGRect(origin: CGPoint(x: size.width - rightInset - sideInset * 2.0 - rightSize.width, y: 0.0), size: CGSize(width: rightSize.width + sideInset * 2.0, height: size.height - bottomInset)) self.middleButton.frame = CGRect(origin: CGPoint(x: floor((size.width - middleSize.width) / 2.0), y: 0.0), size: CGSize(width: middleSize.width + sideInset * 2.0, height: size.height - bottomInset)) } @objc private func leftPressed() { self.left() } @objc private func rightPressed() { self.right() } @objc private func middlePressed() { self.middle() } }