Skip to content

Instantly share code, notes, and snippets.

@churabou
Last active October 8, 2020 03:16
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save churabou/8057aedcf91333bce49aa43a656244ce to your computer and use it in GitHub Desktop.
Save churabou/8057aedcf91333bce49aa43a656244ce to your computer and use it in GitHub Desktop.
final class TooltipView: UIView {
private var option: Option!
init(option: Option) {
self.option = option
super.init(frame: .zero)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private let titleLabel = PaddingLabel()
override func draw(_ rect: CGRect) {
let top: CGFloat = rect.minY + option.arrowHeight + option.lineWidth
let left: CGFloat = rect.minX + option.arrowWidth + option.lineWidth
let right: CGFloat = rect.maxX - option.arrowWidth - option.lineWidth
let bottom: CGFloat = rect.maxY - option.arrowHeight - option.lineWidth
let topLeft = CGPoint(x: left + option.radius, y: top + option.radius)
let topRight = CGPoint(x: right - option.radius, y: top + option.radius)
let bottomLeft = CGPoint(x: left + option.radius, y: bottom - option.radius)
let bottomRight = CGPoint(x: right - option.radius, y: bottom - option.radius)
let path = UIBezierPath()
path.addArc(
withCenter: topLeft,
radius: option.radius,
startAngle: .pi,
endAngle: 3 * .pi / 2,
clockwise: true
)
switch option.arrowPosition {
case let .top(normalizedArrowPointX):
let centerX = rect.width * normalizedArrowPointX
path.addLine(to: CGPoint(x: centerX - option.arrowWidth / 2, y: top))
path.addLine(to: CGPoint(x: centerX, y: rect.minY))
path.addLine(to: CGPoint(x: centerX + option.arrowWidth / 2 , y: top))
default: break
}
path.addLine(to: CGPoint(x: topRight.x, y: top))
path.addArc(
withCenter: topRight,
radius: option.radius,
startAngle: -.pi / 2,
endAngle: 0,
clockwise: true
)
switch option.arrowPosition {
case let .right(normalizedArrowPointY):
let centerY = rect.height * normalizedArrowPointY
path.addLine(to: CGPoint(x: right, y: centerY - option.arrowHeight / 2))
path.addLine(to: CGPoint(x: rect.maxX, y: centerY))
path.addLine(to: CGPoint(x: right, y: centerY + option.arrowHeight / 2))
default: break
}
path.addLine(to: CGPoint(x: right, y: bottomRight.y))
path.addArc(
withCenter: bottomRight,
radius: option.radius,
startAngle: 0,
endAngle: .pi / 2,
clockwise: true
)
switch option.arrowPosition {
case let .bottom(normalizedArrowPointX):
let centerX = rect.width * normalizedArrowPointX
path.addLine(to: CGPoint(x: centerX + option.arrowWidth / 2, y: bottom))
path.addLine(to: CGPoint(x: centerX, y: rect.maxY))
path.addLine(to: CGPoint(x: centerX - option.arrowWidth / 2 , y: bottom))
default: break
}
path.addLine(to: CGPoint(x: bottomLeft.x, y: bottom))
path.addArc(
withCenter: bottomLeft,
radius: option.radius,
startAngle: .pi / 2,
endAngle: .pi,
clockwise: true
)
switch option.arrowPosition {
case let .left(normalizedArrowPointY):
let centerY = rect.height * normalizedArrowPointY
path.addLine(to: CGPoint(x: left, y: centerY + option.arrowHeight / 2))
path.addLine(to: CGPoint(x: rect.minX, y: centerY))
path.addLine(to: CGPoint(x: left, y: centerY - option.arrowHeight / 2))
default: break
}
path.addLine(to: CGPoint(x: left, y: topLeft.y))
option.fillColor.setFill()
option.strokeColor.setStroke()
path.lineWidth = option.lineWidth
path.fill()
path.stroke()
}
}
private extension TooltipView {
func configure() {
addSubview(titleLabel)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
titleLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: option.arrowWidth + option.lineWidth),
titleLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: -option.arrowWidth - option.lineWidth),
titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: option.arrowHeight+option.lineWidth),
titleLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -option.arrowHeight-option.lineWidth),
])
titleLabel.attributedText = option.attributeText
titleLabel.padding = option.padding
}
}
enum ArrowPosition {
case top(normalizedPointX: CGFloat)
case bottom(normalizedPointX: CGFloat)
case left(normalizedPointY: CGFloat)
case right(normalizedPointY: CGFloat)
}
struct Option {
let fillColor: UIColor
let strokeColor: UIColor
let attributeText: NSAttributedString
let padding: UIEdgeInsets
let arrowWidth: CGFloat
let arrowHeight: CGFloat
let radius: CGFloat
let lineWidth: CGFloat
let arrowPosition: ArrowPosition
init(
fillColor: UIColor = UIColor(hex: "f59542"),
strokeColor: UIColor = .white,
attributeText: NSAttributedString = NSAttributedString(
string: "Tootlip",
attributes: [
.foregroundColor: UIColor.white,
.font: UIFont.systemFont(ofSize: 14),
]),
padding: UIEdgeInsets = UIEdgeInsets(top: 2, left: 4, bottom: 2, right: 4),
arrowWidth: CGFloat = 7,
arrowHeight: CGFloat = 4.5,
radius: CGFloat = 4,
lineWidth: CGFloat = 2,
arrowPosition: ArrowPosition = .bottom(normalizedPointX: 0.6)
) {
self.fillColor = fillColor
self.strokeColor = strokeColor
self.attributeText = attributeText
self.padding = padding
self.arrowWidth = arrowWidth
self.arrowHeight = arrowHeight
self.radius = radius
self.lineWidth = lineWidth
self.arrowPosition = arrowPosition
}
}
final class PaddingLabel: UILabel {
var padding: UIEdgeInsets = .zero
override func drawText(in rect: CGRect) {
super.drawText(in: rect.inset(by: padding))
}
override var intrinsicContentSize: CGSize {
var size = super.intrinsicContentSize
size.width += padding.left + padding.right
size.height += padding.top + padding.bottom
return size
}
}
@churabou
Copy link
Author

Example

    let toolTip = TooltipView(option: Option(
        fillColor: UIColor(0xf59542)
        attributeText: NSAttributedString(
            string: "Top: #f59542",
            attributes: [
                .foregroundColor: UIColor.white,
                .font: UIFont.systemFont(ofSize: 14),
            ]
        ),
        padding: UIEdgeInsets(top: 2, left: 4, bottom: 2, right: 4),
        arrowPosition: .bottom(normalizedPointX: 0.4)
    ))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment