AlertControllerNode: use blurred effect view for background

TextAlertController: exposed TextAlertContentActionNode
This commit is contained in:
Ilya Laktyushin
2019-06-08 00:06:23 +02:00
parent a72ebae781
commit 7657cdb00a
2 changed files with 94 additions and 35 deletions

View File

@@ -3,9 +3,15 @@ import UIKit
import AsyncDisplayKit
final class AlertControllerNode: ASDisplayNode {
private let dimmingNode: ASDisplayNode
private let centerDimView: UIImageView
private let topDimView: UIView
private let bottomDimView: UIView
private let leftDimView: UIView
private let rightDimView: UIView
private let containerNode: ASDisplayNode
private let effectNode: ASDisplayNode
private let backgroundNode: ASDisplayNode
private let contentNode: AlertContentNode
private let allowInputInset: Bool
@@ -15,14 +21,35 @@ final class AlertControllerNode: ASDisplayNode {
init(contentNode: AlertContentNode, theme: AlertControllerTheme, allowInputInset: Bool) {
self.allowInputInset = allowInputInset
self.dimmingNode = ASDisplayNode()
self.dimmingNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
let dimColor = UIColor(white: 0.0, alpha: 0.5)
self.centerDimView = UIImageView()
self.centerDimView.image = generateStretchableFilledCircleImage(radius: 16.0, color: nil, backgroundColor: dimColor)
self.topDimView = UIView()
self.topDimView.backgroundColor = dimColor
self.topDimView.isUserInteractionEnabled = false
self.bottomDimView = UIView()
self.bottomDimView.backgroundColor = dimColor
self.bottomDimView.isUserInteractionEnabled = false
self.leftDimView = UIView()
self.leftDimView.backgroundColor = dimColor
self.leftDimView.isUserInteractionEnabled = false
self.rightDimView = UIView()
self.rightDimView.backgroundColor = dimColor
self.rightDimView.isUserInteractionEnabled = false
self.containerNode = ASDisplayNode()
self.containerNode.backgroundColor = theme.backgroundColor
self.containerNode.layer.cornerRadius = 14.0
self.containerNode.layer.masksToBounds = true
self.backgroundNode = ASDisplayNode()
self.backgroundNode.backgroundColor = theme.backgroundColor
self.effectNode = ASDisplayNode(viewBlock: {
return UIVisualEffectView(effect: UIBlurEffect(style: theme.backgroundType == .light ? .light : .dark))
})
@@ -31,10 +58,14 @@ final class AlertControllerNode: ASDisplayNode {
super.init()
self.addSubnode(self.dimmingNode)
self.addSubnode(self.effectNode)
self.view.addSubview(self.centerDimView)
self.view.addSubview(self.topDimView)
self.view.addSubview(self.bottomDimView)
self.view.addSubview(self.leftDimView)
self.view.addSubview(self.rightDimView)
self.containerNode.addSubnode(self.effectNode)
self.containerNode.addSubnode(self.backgroundNode)
self.containerNode.addSubnode(self.contentNode)
self.addSubnode(self.containerNode)
@@ -48,7 +79,8 @@ final class AlertControllerNode: ASDisplayNode {
override func didLoad() {
super.didLoad()
self.dimmingNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimmingNodeTapGesture(_:))))
self.topDimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimmingNodeTapGesture(_:))))
self.bottomDimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimmingNodeTapGesture(_:))))
}
func updateTheme(_ theme: AlertControllerTheme) {
@@ -60,13 +92,21 @@ final class AlertControllerNode: ASDisplayNode {
}
func animateIn() {
self.dimmingNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.centerDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.topDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.bottomDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.leftDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.rightDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
self.containerNode.layer.animateSpring(from: 0.8 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, removeOnCompletion: true, additive: false, completion: nil)
}
func animateOut(completion: @escaping () -> Void) {
self.dimmingNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
self.centerDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
self.topDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
self.bottomDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
self.leftDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
self.rightDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
self.containerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
self.containerNode.layer.animateScale(from: 1.0, to: 0.8, duration: 0.4, removeOnCompletion: false, completion: { _ in
completion()
@@ -76,8 +116,6 @@ final class AlertControllerNode: ASDisplayNode {
func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
self.containerLayout = layout
transition.updateFrame(node: self.dimmingNode, frame: CGRect(origin: CGPoint(), size: layout.size))
var insetOptions: ContainerViewLayoutInsetOptions = [.statusBar]
if self.allowInputInset {
insetOptions.insert(.input)
@@ -91,8 +129,15 @@ final class AlertControllerNode: ASDisplayNode {
let containerSize = CGSize(width: contentSize.width, height: contentSize.height)
let containerFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - containerSize.width) / 2.0), y: contentAvailableFrame.minY + floor((contentAvailableFrame.size.height - containerSize.height) / 2.0)), size: containerSize)
transition.updateFrame(view: self.centerDimView, frame: containerFrame)
transition.updateFrame(view: self.topDimView, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: containerFrame.minY)))
transition.updateFrame(view: self.bottomDimView, frame: CGRect(origin: CGPoint(x: 0.0, y: containerFrame.maxY), size: CGSize(width: layout.size.width, height: layout.size.height - containerFrame.maxY)))
transition.updateFrame(view: self.leftDimView, frame: CGRect(origin: CGPoint(x: 0.0, y: containerFrame.minY), size: CGSize(width: containerFrame.minX, height: containerFrame.height)))
transition.updateFrame(view: self.rightDimView, frame: CGRect(origin: CGPoint(x: containerFrame.maxX, y: containerFrame.minY), size: CGSize(width: layout.size.width - containerFrame.maxX, height: containerFrame.height)))
transition.updateFrame(node: self.containerNode, frame: containerFrame)
transition.updateFrame(node: self.effectNode, frame: containerFrame)
transition.updateFrame(node: self.effectNode, frame: CGRect(origin: CGPoint(), size: containerFrame.size))
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: containerFrame.size))
transition.updateFrame(node: self.contentNode, frame: CGRect(origin: CGPoint(), size: containerFrame.size))
}

View File

@@ -22,18 +22,20 @@ public struct TextAlertAction {
}
}
private final class TextAlertContentActionNode: HighlightableButtonNode {
private let backgroundNode: ASDisplayNode
public final class TextAlertContentActionNode: HighlightableButtonNode {
private var theme: AlertControllerTheme
let action: TextAlertAction
init(theme: AlertControllerTheme, action: TextAlertAction) {
private let backgroundNode: ASDisplayNode
public init(theme: AlertControllerTheme, action: TextAlertAction) {
self.theme = theme
self.action = action
self.backgroundNode = ASDisplayNode()
self.backgroundNode.isLayerBacked = true
self.backgroundNode.alpha = 0.0
self.action = action
super.init()
self.titleNode.maximumNumberOfLines = 2
@@ -56,16 +58,27 @@ private final class TextAlertContentActionNode: HighlightableButtonNode {
self.updateTheme(theme)
}
func updateTheme(_ theme: AlertControllerTheme) {
public var actionEnabled: Bool = true {
didSet {
self.isUserInteractionEnabled = self.actionEnabled
self.updateTitle()
}
}
public func updateTheme(_ theme: AlertControllerTheme) {
self.theme = theme
self.backgroundNode.backgroundColor = theme.highlightedItemColor
self.updateTitle()
}
private func updateTitle() {
var font = Font.regular(17.0)
var color = theme.accentColor
var color: UIColor
switch self.action.type {
case .defaultAction, .genericAction:
break
color = self.actionEnabled ? self.theme.accentColor : self.theme.disabledColor
case .destructiveAction:
color = theme.destructiveColor
color = self.actionEnabled ? self.theme.destructiveColor : self.theme.disabledColor
}
switch self.action.type {
case .defaultAction:
@@ -76,7 +89,7 @@ private final class TextAlertContentActionNode: HighlightableButtonNode {
self.setAttributedTitle(NSAttributedString(string: self.action.title, font: font, textColor: color, paragraphAlignment: .center), for: [])
}
override func didLoad() {
override public func didLoad() {
super.didLoad()
self.addTarget(self, action: #selector(self.pressed), forControlEvents: .touchUpInside)
@@ -86,7 +99,7 @@ private final class TextAlertContentActionNode: HighlightableButtonNode {
self.action.action()
}
override func layout() {
override public func layout() {
super.layout()
self.backgroundNode.frame = self.bounds
@@ -203,16 +216,17 @@ public final class TextAlertContentNode: AlertContentNode {
override public func updateTheme(_ theme: AlertControllerTheme) {
self.theme = theme
let textFont: UIFont
if let titleNode = self.titleNode {
titleNode.attributedText = NSAttributedString(string: titleNode.attributedText?.string ?? "", font: Font.medium(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
textFont = Font.regular(13.0)
} else {
textFont = Font.semibold(17.0)
if let titleNode = self.titleNode, let attributedText = titleNode.attributedText {
let updatedText = NSMutableAttributedString(attributedString: attributedText)
updatedText.addAttribute(NSAttributedStringKey.foregroundColor, value: theme.primaryColor, range: NSRange(location: 0, length: updatedText.length))
titleNode.attributedText = updatedText
}
self.textNode.attributedText = NSAttributedString(string: self.textNode.attributedText?.string ?? "", font: textFont, textColor: theme.primaryColor, paragraphAlignment: .center)
if let attributedText = self.textNode.attributedText {
let updatedText = NSMutableAttributedString(attributedString: attributedText)
updatedText.addAttribute(NSAttributedStringKey.foregroundColor, value: theme.primaryColor, range: NSRange(location: 0, length: updatedText.length))
self.textNode.attributedText = updatedText
}
self.actionNodesSeparator.backgroundColor = theme.separatorColor
for actionNode in self.actionNodes {
actionNode.updateTheme(theme)