心形流水燈製作
1.效果圖
2.實現程式碼
// MARK: -XJHeartView
class XJHeartView: UIView {
// 圓半徑
let R: CGFloat = 100
// 繪製路徑
var pathArray: [UIBezierPath] = []
// 所有的view
var allArray: [UIView] = []
// 左邊
var leftArray: [UIView] = []
// 右邊
var rightArray: [UIView] = []
// 左上邊
var leftUpArray: [UIView] = []
// 左下邊
var leftDownArray: [UIView] = []
// 右上邊
var rightUpArray: [UIView] = []
// 右下邊
var rightDownArray: [UIView] = []
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.white
let centerX = self.width * 0.5
let centerY = self.height * 0.5
// (centerX ,centerY + sqrt(2)R)
// (centerX - sqrt(2)R ,centerY)
// (centerX + sqrt(2)R ,centerY)
// (centerX - sqrt(2)R * 0.5 ,centerY - sqrt(2)R * 0.5)
// (centerX + sqrt(2)R * 0.5 ,centerY - sqrt(2)R * 0.5)
let lLine = UIBezierPath()
lLine.move(to: CGPoint(x: centerX, y: centerY + sqrt(2) * R))
lLine.addLine(to: CGPoint(x: centerX - sqrt(2) * R, y: centerY))
let lArc = UIBezierPath(arcCenter: CGPoint(x: centerX - sqrt(2) * R * 0.5, y: centerY - sqrt(2) * R * 0.5), radius: R, startAngle: CGFloat(Double.pi * 0.75), endAngle: CGFloat(Double.pi * 1.75), clockwise: true)
let rArc = UIBezierPath(arcCenter: CGPoint(x: centerX + sqrt(2) * R * 0.5, y: centerY - sqrt(2) * R * 0.5), radius: R, startAngle: CGFloat(Double.pi * 1.25), endAngle: CGFloat(Double.pi * 2.25), clockwise: true)
let rLine = UIBezierPath()
rLine.move(to: CGPoint(x: centerX + sqrt(2) * R, y: centerY))
rLine.addLine(to: CGPoint(x: centerX, y: centerY + sqrt(2) * R))
pathArray.append(lLine)
pathArray.append(lArc)
pathArray.append(rArc)
pathArray.append(rLine)
let rightCenter = CGPoint(x: centerX + sqrt(2) * R * 0.5, y: centerY - sqrt(2) * R * 0.5)
let leftCenter = CGPoint(x: centerX - sqrt(2) * R * 0.5, y: centerY - sqrt(2) * R * 0.5)
// 右上
for i in 0..<8 {
let view = UIView()
view.backgroundColor = extinctColor
self.addSubview(view)
view.layer.cornerRadius = 5
view.layer.masksToBounds = true
view.size = CGSize(width: 10, height: 10)
view.center = getPointCenter(center: rightCenter, angle: CGFloat(-20 + i * 20))
rightUpArray.append(view)
}
// 右下
for b in 0..<8 {
let view = UIView()
view.backgroundColor = extinctColor
self.addSubview(view)
view.layer.cornerRadius = 5
view.layer.masksToBounds = true
view.size = CGSize(width: 10, height: 10)
let offsetX: CGFloat = CGFloat(b) * (CGFloat(sqrt(2) * R) / 7) + 10.0
view.center = CGPoint(x: centerX + offsetX, y: centerY + (CGFloat(sqrt(2) * R) - offsetX))
rightDownArray.append(view)
}
// 左上
for j in 0..<8 {
let view = UIView()
view.backgroundColor = extinctColor
self.addSubview(view)
view.layer.cornerRadius = 5
view.layer.masksToBounds = true
view.size = CGSize(width: 10, height: 10)
view.center = getPointCenter(center: leftCenter, angle: CGFloat(60 + j * 20))
leftUpArray.append(view)
}
// 左下
for a in 0..<8 {
let view = UIView()
view.backgroundColor = extinctColor
self.addSubview(view)
view.layer.cornerRadius = 5
view.layer.masksToBounds = true
view.size = CGSize(width: 10, height: 10)
let offsetX: CGFloat = CGFloat(a) * (CGFloat(sqrt(2) * R) / 7) + 10.0
view.center = CGPoint(x: centerX - offsetX, y: centerY + (CGFloat(sqrt(2) * R) - offsetX))
leftDownArray.append(view)
}
// 順時針360
rightUpArray = rightUpArray.reversed()
rightDownArray = rightDownArray.reversed()
leftUpArray = leftUpArray.reversed()
allArray = rightUpArray + rightDownArray + leftDownArray + leftUpArray
// 逆時針180
leftArray = leftUpArray.reversed()
leftArray.append(leftDownArray.reversed())
// 順時針180
rightArray = rightUpArray + rightDownArray
}
func getPointCenter(center: CGPoint, angle: CGFloat) -> CGPoint {
let x = 100 * cosf(Float(angle * CGFloat(Double.pi) / 180))
let y = 100 * sinf(Float(angle * CGFloat(Double.pi) / 180))
return CGPoint(x: center.x + CGFloat(x), y: center.y - CGFloat(y))
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
for path in self.pathArray {
UIColor.red.set()
path.lineWidth = 1
path.lineCapStyle = .round
path.lineJoinStyle = .round
path.stroke()
}
}
}
// MARK: -
XJHeartViewController
/// 迴圈次數
var loopIndex: Int = 0
/// 迴圈時間
var timeInterval: TimeInterval = 0.2
// 熄滅顏色
let extinctColor = UIColor.blue
// 點亮顏色
let lightingColor = UIColor.red
class XJHeartViewController: XJBaseViewController {
lazy var heartView: XJHeartView = {
let heart = XJHeartView(frame: self.view.bounds)
return heart
}()
/// 定時器
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
loopIndex = 0
self.title = "流水燈"
self.view.addSubview(heartView)
self.createTimer(timeInterval, isFire: false)
}
/// 建立定時器
func createTimer(_ timeInterval: TimeInterval, isFire: Bool) {
timer = Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: true) {[weak self] (timer) in
guard let self = self else { return }
self.executionTimer()
}
if isFire {
// timer?.fireDate = .distantPast
} else {
timer?.fireDate = .distantFuture
}
}
/// 銷燬定時器
func invalidateTimer() {
guard let timer = timer else { return }
timer.invalidate()
}
/// 觸發定時器
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
timer?.fireDate = .distantPast
}
/// 點選返回
override func backBtnClick(_ button: UIButton) {
self.invalidateTimer()
super.backBtnClick(button)
}
/// 熄滅所有
func extinctAll() {
for view in heartView.allArray {
view.backgroundColor = extinctColor
}
}
/// 執行定時器
func executionTimer() {
let index = loopIndex % heartView.allArray.count
let loopNum = loopIndex / heartView.allArray.count
print("\(loopIndex)---\(index)---\(loopNum)")
// 迴圈一週
if index == 0 && loopIndex != 0 {
// 熄滅所有
self.extinctAll()
// 下次迴圈時間
let loopTime = timeInterval - Double(loopNum) * 0.05
if loopTime == 0 { return }
// 銷燬舊定時器
self.invalidateTimer()
// 創新新定時器
self.createTimer(loopTime, isFire: true)
}
let view = heartView.allArray[index]
view.backgroundColor = lightingColor
loopIndex += 1
}
}
3.詳細程式碼