我試圖創建某種時間線(用Vector Illustrator的心態),使用UIBezier和UI Label(有點像在日歷應用程式中),然后使用UIPanGestureRecognizer來向上和向下滾動。但是,每當我在模擬器中滾動它時,它就會自我繁殖,而不是像下面的圖片那樣移動(我在滾動值變化時使用setNeedsDisplay來重新繪制整個機制)。這可能是我的一個小錯誤,也可能是我的代碼不起作用。
我知道我可以使用 UIScrollView 或 UITableView 來代替,但是我試著將其作為一個小的挑戰,作為一個定制的表格,因為對于像我這樣習慣于 CAD 繪圖或 Vector Illustrator 的人來說,使用預制物件感覺很受限制。

我使用的代碼如下:
import UIKit
class ViewController。UIViewController {
var tlobject = TimelineView()
let gesto = UIPanGestureRecognizer()
override func viewDidLoad() {
super.viewDidLoad()
//===== 添加時間線視圖物件到視圖中。
let TLObjectFrame = CGRect(x: 0, y: 40, width: 100, height: 100)
tlobject = TimelineView( frame: TLObjectFrame)
view.addSubview(tlobject)
//===== ADD TOUCH GESTURE =====
gesto.addTarget(self, action: #selector(touchinput))
view.addGestureRecognizer(gesto)
}
var touchStartLocation: Int = 0
var scrollDistance: Int = 0
var lastScrollDistance: Int = 0
//下面的函式計算觸摸手勢在YA軸上滾動/移動的距離,并將結果值(scrollDistance)發送到時間軸機制,它定義了每個UIBezier的Y位置。感謝Youtube上的Mitchell Hudson在他的教程 "06 11觸摸值 "中幫助我解決了這個問題。
@objc func touchinput (sender: UIPanGestureRecognizer) {
if sender.state == UIGestureRecognizer.State.start{
touchStartLocation = Int(sender.location(in: view).y)
LastScrollDistance = scrollDistance
}
if sender.state == UIGestureRecognizer.State.change {
let touchEndLocation = Int(sender.location(in: view).y)
let currentScrollDistance = touchEndLocation - touchStartLocation
print("deltaY"/span>, currentScrollDistance)
var newScrollDistance = lastScrollDistance currentScrollDistance
scrollDistance = newScrollDistance
tlobject.totalScrollDistance = scrollDistance //send scrollValue to TimelineView[/span]。
}
if sender.state == UIGestureRecognizer.State. ended {
print("lastScrollDistance"/span>, lastScrollDistance)
print("roll Distance", scrollDistance)
}
}
}
//Created a new View with the TimeLine mechanism[/span]。
class TimelineView。UIView {
var totalScrollDistance: Int = 0 {
didSet{
setNeedsDisplay() //每次UIgesture位置改變時都會呼叫這個。
}
}
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.clear
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented"/span>)
}
override func draw(_ rect: CGRect) {
時間機制()
}
func timelinemechanism() {
let lineElements: Array = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let間距。Int = 30
let scrollDistance: Int = totalScrollDistance.
let totalElements: Int = lineElements.count
for n in 1.../span>totalElements {
//Get UILabel/UILine Yposition on screen = Array index number * the spacing scroll distance by touch pan gesture。
let yPosition = lineElements[n - 1] * spacing scrollDistance
let linepath = UIBezierPath()
linepath.move(to: CGPoint(x: 60, y: yPosition)
linepath.addLine(to: CGPoint(x: 300, y: yPosition)
let lineshape = CAShapeLayer()
lineshape.path = linepath.cgPath
lineshape.strokeColor = UIColor.blue.cgColor
//lineshape.fillColor = UIColor.white.cgColor。
//lineshape.lineWidth = 1
self.layer.addSublayer(lineshape)。
let hourlabel = UILabel()
hourlabel.frame = CGRect(x: 5, y: yPosition - 20, width: 45, height: 40)
hourlabel.text = "(n):00"。
/hourlabel.font = UIFont(name: "Avenir-Claro", size: 12)
hourlabel.textColor = UIColor.blue
hourlabel.textAlignment = NSTextAlignment.right
self.addSubview(hourlabel)
}
}
}
uj5u.com熱心網友回復:
在draw里面,你只需要畫一些東西。你添加新的子視圖/子版面,而不洗掉舊的子視圖/子版面。
每當你改變一個幀時,創建一個新的視圖是非常耗費資源的。而你不需要這樣做,因為你有相同的視圖,你只需要改變位置。
相反,你可以創建一個新的視圖。
相反,你可以在開始時創建你的視圖并使用layoutSubviews來更新你的視圖位置:
class TimelineView。UIView {
var totalScrollDistance: Int = 0 {
didSet{
setNeedsLayout() //每次UIgesture位置改變時都會呼叫這個。
}
}
private var lastLayoutTotalScrollDistance: Int = 0
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.clear
createTimelinemechanism()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented"/span>)
}
var lineShapes = [CAShapeLayer] ()
var hourLabels = [UILabel]()
override func layoutSubviews() {
super.layoutSubviews()
let offset = totalScrollDistance - lastLayoutTotalScrollDistance
lastLayoutTotalScrollDistance = totalScrollDistance
lineShapes.forEach { lineShape in.
lineShape.frame.origin.y = CGFloat(offset)
}
hourLabels.forEach { hourLabel in
hourLabel.frame.origin.y = CGFloat(offset)
}
}
func createTimelinemechanism() {
let lineElements: Array = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let間距。Int = 30
let totalElements: Int = lineElements.count
for n in 1.../span>totalElements {
//Get UILabel/UILine Yposition on screen = Array index number * the spacing scroll distance by touch pan gesture。
let yPosition = lineElements[n - 1] * spacing
let linepath = UIBezierPath()
linepath.move(to: CGPoint(x: 60, y: yPosition)
linepath.addLine(to: CGPoint(x: 300, y: yPosition)
let lineshape = CAShapeLayer()
lineshape.path = linepath.cgPath
lineshape.strokeColor = UIColor.blue.cgColor
//lineshape.fillColor = UIColor.white.cgColor。
//lineshape.lineWidth = 1
//disable default layer position animation
lineshape.actions = [
"position": NSNull(),
]
self.layer.addSublayer(lineshape)
lineShapes.append(lineshape)
let hourlabel = UILabel()
hourlabel.frame = CGRect(x: 5, y: yPosition - 20, width: 45, height: 40)
hourlabel.text = "(n):00"。
/hourlabel.font = UIFont(name: "Avenir-Claro", size: 12)
hourlabel.textColor = UIColor.blue
hourlabel.textAlignment = NSTextAlignment.right
self.addSubview(hourlabel)
hourLabels.append(hourlabel)
}
}
}
更普遍的是,你可以直接列出所有的子視圖/子版面,而不把它們放在單獨的容器中。
uj5u.com熱心網友回復:
你需要明確地清除你想要繪制的視圖層的區域,以便在你繪制新的圖形之前,舊的圖形被移除。
你的draw方法:
override func draw(_ rect: CGRect) {
if let cgContext = UIGraphicsGetCurrentContext() {
cgContext.clear(rect)
}
timelinemechanism()
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/324712.html
標籤:
上一篇:如何去除多余的零
