Created
July 9, 2021 10:18
-
-
Save damodarnamala/5ffe5313d339b230b99a06e170d3bdf2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ToolTipView: UILabel { | |
static let shared = ToolTipView() | |
enum Anchor { | |
case leading | |
case trailing | |
case center | |
} | |
private var anchor: Anchor = .leading | |
private var labelTransform: CGAffineTransform! | |
private init() { | |
super.init(frame: .zero) | |
} | |
private override init(frame: CGRect) { | |
super.init(frame: .zero) | |
self.numberOfLines = 0 | |
} | |
required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
} | |
override var intrinsicContentSize: CGSize { | |
let size = super.intrinsicContentSize | |
return CGSize(width: size.width + 9 + 8, | |
height: size.height + 8 + 8) | |
} | |
override var bounds: CGRect { | |
didSet { | |
// ensures this works within stack views if multi-line | |
preferredMaxLayoutWidth = bounds.width - (8 + 8) | |
} | |
} | |
func display(with anchor: Anchor, in view: UIView, below actionView: UIView) { | |
self.anchor = anchor | |
switch anchor { | |
case .center: | |
self.centerXAnchor(equalTo: actionView.centerXAnchor) | |
case .leading: | |
self.leadingAnchor(equalTo: actionView.leadingAnchor, constant: -16) | |
self.trailingAnchor(equalTo: view.trailingAnchor, constant: -16) | |
case .trailing: | |
self.trailingAnchor(equalTo: actionView.trailingAnchor) | |
self.leadingAnchor(equalTo: view.leadingAnchor, constant: 16) | |
} | |
self.centerYAnchor(equalTo: actionView.centerYAnchor, constant: -48) | |
let trans1 = CGAffineTransform(scaleX: 0, y: 0) | |
let trans2 = CGAffineTransform(translationX: 0, y: self.frame.size.height) | |
labelTransform = trans1.concatenating(trans2) | |
self.transform = labelTransform | |
UIView.animate(withDuration: 0.75, delay: 0, | |
usingSpringWithDamping: 0.7, | |
initialSpringVelocity: 0.5, | |
options: .curveEaseIn, | |
animations: { () -> Void in | |
self.transform = .identity | |
}) | |
} | |
override func draw(_ rect: CGRect) { | |
let roundRect = CGRect(x: rect.minX, y: rect.minY, width: rect.width, height: rect.height) | |
textAlignment = .center | |
let trianglePath = UIBezierPath() | |
switch anchor { | |
case .center: | |
trianglePath.move(to: CGPoint(x: roundRect.midX - 12, y: roundRect.maxY)) | |
trianglePath.addLine(to: CGPoint(x: roundRect.midX + 12, y: roundRect.maxY)) | |
trianglePath.addLine(to: CGPoint(x: roundRect.midX, y: roundRect.maxY + 12)) | |
case .leading: | |
trianglePath.move(to: CGPoint(x: roundRect.minX + 24, y: roundRect.maxY)) | |
trianglePath.addLine(to: CGPoint(x: roundRect.minX + 12, y: roundRect.maxY)) | |
trianglePath.addLine(to: CGPoint(x: roundRect.minX + 24, y: roundRect.maxY + 12)) | |
case .trailing: | |
trianglePath.move(to: CGPoint(x: roundRect.maxX - 24, y: roundRect.maxY)) | |
trianglePath.addLine(to: CGPoint(x: roundRect.maxX-12, y: roundRect.maxY)) | |
trianglePath.addLine(to: CGPoint(x: roundRect.maxX-12, y: roundRect.maxY + 12)) | |
} | |
trianglePath.close() | |
let shapeTriangle = CAShapeLayer() | |
shapeTriangle.path = trianglePath.cgPath | |
shapeTriangle.fillColor = UIColor.toolTipColor.cgColor | |
layer.insertSublayer(shapeTriangle, at: 0) | |
let insets = UIEdgeInsets(top: 4, left: 8, bottom: 4, right: 8) | |
let bezierPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: 8) | |
UIColor.toolTipColor.setFill() | |
bezierPath.fill() | |
super.drawText(in: rect.inset(by: insets)) | |
} | |
} | |
extension ToolTipView { | |
func create(with text: String, with anchor: Anchor, placeHolderView: UIView, from actionView: UIView) { | |
self.text = text | |
self.font = UIFont.preferredCustomFont(forTextStyle: .body) | |
self.anchor = anchor | |
placeHolderView.addSubview(self) | |
self.display(with: self.anchor, in: placeHolderView, below: actionView) | |
self.text = text | |
self.numberOfLines = 0 | |
self.textColor = .toolTipTextColor | |
self.setNeedsDisplay() | |
Queue.main(.seconds(4), .userInitiated) { | |
self.removeFromSuperview() | |
} | |
} | |
} | |
extension UIView { | |
func showTooltip(with text: String, behind subview: UIView) { | |
ToolTipView.shared.create(with: text, with: .center, placeHolderView: self, from: subview) | |
} | |
} | |
extension UIColor { | |
static var toolTipColor: UIColor { | |
UIColor(red: 204/255, green: 205/255, blue: 226/255, alpha: 1) | |
} | |
static var toolTipTextColor: UIColor { | |
UIColor(red: 81/255, green: 118/255, blue: 155/255, alpha: 1) | |
} | |
} | |
final class Queue { | |
public static func main(_ after: DispatchTimeInterval = .milliseconds(0), | |
_ service: DispatchQoS = .userInteractive , | |
_ closure: @escaping () -> Void) { | |
DispatchQueue.main.asyncAfter(deadline: .now() + after, | |
qos: service, | |
execute: closure) | |
} | |
public static func onGlobal(_ after: DispatchTimeInterval = .milliseconds(0), | |
_ service: DispatchQoS = .utility , | |
_ closure: @escaping () -> Void) { | |
DispatchQueue.global(qos: .userInitiated) | |
.asyncAfter(deadline: .now() + after, | |
qos: service, | |
execute: closure) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment