Skip to content

Instantly share code, notes, and snippets.

@damodarnamala
Created July 9, 2021 10:18
Show Gist options
  • Save damodarnamala/5ffe5313d339b230b99a06e170d3bdf2 to your computer and use it in GitHub Desktop.
Save damodarnamala/5ffe5313d339b230b99a06e170d3bdf2 to your computer and use it in GitHub Desktop.
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