Swiftgram/Display/NavigationButtonNode.swift
2017-02-11 17:02:35 +03:00

200 lines
6.9 KiB
Swift

import UIKit
import AsyncDisplayKit
public class NavigationButtonNode: ASTextNode {
private func fontForCurrentState() -> UIFont {
return self.bold ? UIFont.boldSystemFont(ofSize: 17.0) : UIFont.systemFont(ofSize: 17.0)
}
private func attributesForCurrentState() -> [String : AnyObject] {
return [
NSFontAttributeName: self.fontForCurrentState(),
NSForegroundColorAttributeName: self.isEnabled ? self.color : UIColor.gray
]
}
private var _text: String?
public var text: String {
get {
return _text ?? ""
}
set(value) {
_text = value
self.attributedText = NSAttributedString(string: text, attributes: self.attributesForCurrentState())
}
}
private var imageNode: ASImageNode?
private var _image: UIImage?
public var image: UIImage? {
get {
return _image
} set(value) {
_image = value
if let _ = value {
if self.imageNode == nil {
let imageNode = ASImageNode()
imageNode.displayWithoutProcessing = true
imageNode.displaysAsynchronously = false
self.imageNode = imageNode
self.addSubnode(imageNode)
}
self.imageNode?.image = image
} else if let imageNode = self.imageNode {
imageNode.removeFromSupernode()
self.imageNode = nil
}
self.invalidateCalculatedLayout()
self.setNeedsLayout()
}
}
public var node: ASDisplayNode? {
didSet {
if self.node !== oldValue {
oldValue?.removeFromSupernode()
if let node = self.node {
self.addSubnode(node)
self.invalidateCalculatedLayout()
self.setNeedsLayout()
}
}
}
}
public var color: UIColor = UIColor(0x007ee5) {
didSet {
if let text = self._text {
self.attributedText = NSAttributedString(string: text, attributes: self.attributesForCurrentState())
}
}
}
private var _bold: Bool = false
public var bold: Bool {
get {
return _bold
}
set(value) {
if _bold != value {
_bold = value
self.attributedText = NSAttributedString(string: text, attributes: self.attributesForCurrentState())
}
}
}
private var touchCount = 0
public var pressed: () -> () = { }
public var highlightChanged: (Bool) -> () = { _ in }
public override init() {
super.init()
self.isUserInteractionEnabled = true
self.isExclusiveTouch = true
self.hitTestSlop = UIEdgeInsets(top: -16.0, left: -10.0, bottom: -16.0, right: -10.0)
self.displaysAsynchronously = false
}
override public func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
let superSize = super.calculateSizeThatFits(constrainedSize)
if let node = self.node {
let nodeSize = node.measure(constrainedSize)
return CGSize(width: max(nodeSize.width, superSize.width), height: max(nodeSize.height, superSize.height))
} else if let imageNode = self.imageNode {
let nodeSize = imageNode.measure(constrainedSize)
let size = CGSize(width: max(nodeSize.width, superSize.width), height: max(nodeSize.height, superSize.height))
imageNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - nodeSize.width) / 2.0), y: floorToScreenPixels((size.height - nodeSize.height) / 2.0)), size: nodeSize)
return size
}
return superSize
}
override public func layout() {
super.layout()
if let node = self.node {
node.frame = CGRect(origin: CGPoint(), size: node.calculatedSize)
}
}
private func touchInsideApparentBounds(_ touch: UITouch) -> Bool {
var apparentBounds = self.bounds
let hitTestSlop = self.hitTestSlop
apparentBounds.origin.x += hitTestSlop.left
apparentBounds.size.width -= hitTestSlop.left + hitTestSlop.right
apparentBounds.origin.y += hitTestSlop.top
apparentBounds.size.height -= hitTestSlop.top + hitTestSlop.bottom
return apparentBounds.contains(touch.location(in: self.view))
}
public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
self.touchCount += touches.count
self.updateHighlightedState(true, animated: false)
}
public override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
self.updateHighlightedState(self.touchInsideApparentBounds(touches.first!), animated: true)
}
public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
self.updateHighlightedState(false, animated: false)
let previousTouchCount = self.touchCount
self.touchCount = max(0, self.touchCount - touches.count)
if previousTouchCount != 0 && self.touchCount == 0 && self.isEnabled && self.touchInsideApparentBounds(touches.first!) {
self.pressed()
}
}
public override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
self.touchCount = max(0, self.touchCount - (touches?.count ?? 0))
self.updateHighlightedState(false, animated: false)
}
private var _highlighted = false
private func updateHighlightedState(_ highlighted: Bool, animated: Bool) {
if _highlighted != highlighted {
_highlighted = highlighted
let alpha: CGFloat = !self.isEnabled ? 1.0 : (highlighted ? 0.4 : 1.0)
/*if animated {
UIView.animate(withDuration: 0.3, delay: 0.0, options: UIViewAnimationOptions.beginFromCurrentState, animations: { () -> Void in
self.alpha = alpha
}, completion: nil)
}
else {*/
self.alpha = alpha
self.highlightChanged(highlighted)
//}
}
}
public override var isEnabled: Bool {
get {
return super.isEnabled
}
set(value) {
if self.isEnabled != value {
super.isEnabled = value
self.attributedString = NSAttributedString(string: text, attributes: self.attributesForCurrentState())
}
}
}
}