forked from SwiftKickMobile/SwiftMessages
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCornerRoundingView.swift
83 lines (71 loc) · 2.88 KB
/
CornerRoundingView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//
// CornerRoundingView.swift
// SwiftMessages
//
// Created by Timothy Moose on 7/28/18.
// Copyright © 2018 SwiftKick Mobile. All rights reserved.
//
import UIKit
/// A background view that messages can use for rounding all or a subset of corners with squircles
/// (the smoother method of rounding corners that you see on app icons).
open class CornerRoundingView: UIView {
/// Specifies the corner radius to use.
@IBInspectable
open var cornerRadius: CGFloat = 0 {
didSet {
updateMaskPath()
}
}
/// Set to `true` for layouts where only the leading corners should be
/// rounded. For example, the layout in TabView.xib rounds the bottom corners
/// when displayed from the top and the top corners when displayed from the bottom.
/// When this property is `true`, the `roundedCorners` property will be overwritten
/// by relevant animators (e.g. `TopBottomAnimation`).
@IBInspectable
open var roundsLeadingCorners: Bool = false
/// Specifies which corners should be rounded. When `roundsLeadingCorners = true`, relevant
/// relevant animators (e.g. `TopBottomAnimation`) will overwrite the value of this property.
open var roundedCorners: UIRectCorner = [.allCorners] {
didSet {
updateMaskPath()
}
}
override public init(frame: CGRect) {
super.init(frame: frame)
sharedInit()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
sharedInit()
}
private func sharedInit() {
layer.mask = shapeLayer
}
private let shapeLayer = CAShapeLayer()
override open func layoutSubviews() {
super.layoutSubviews()
updateMaskPath()
}
private func updateMaskPath() {
let newPath = UIBezierPath(roundedRect: layer.bounds, byRoundingCorners: roundedCorners, cornerRadii: cornerRadii).cgPath
// Update the `shapeLayer's` path with animation if we detect our `layer's` size is being animated.
// This is a workaround needed for smooth rotation animations.
if let foundAnimation = layer.findAnimation(forKeyPath: "bounds.size") {
// Update the `shapeLayer's` path with animation, copying the relevant properties
// from the found animation.
let animation = CABasicAnimation(keyPath: "path")
animation.duration = foundAnimation.duration
animation.timingFunction = foundAnimation.timingFunction
animation.fromValue = shapeLayer.path
animation.toValue = newPath
shapeLayer.add(animation, forKey: "path")
shapeLayer.path = newPath
} else {
// Update the `shapeLayer's` path without animation
shapeLayer.path = newPath
}
}
private var cornerRadii: CGSize {
return CGSize(width: cornerRadius, height: cornerRadius)
}
}