在 Swift 中更新视图
update view in Swift
我正在制作一个应用程序,通过从数组中读取 CGPoint 并相应地设置图像的中心,以编程方式在屏幕上移动图像。最简单的形式是这样的:
for point in array {
image.center = point
sleep(1)
}
它发生在按下按钮之后,因此 for 循环位于按钮的 @IBAction func ...
内。
问题是屏幕在 image.center
更改后没有更新,而是在整个 for 循环完成后才更新,所以当图像位于数组的最后一个点时。如何强制更新视图?或者通常处理此问题的最佳方法是什么?
按照@matt 的建议移除睡眠,并尝试在图像的父视图上调用方法 layoutifneeded 而不是睡眠。视图需要重绘,所以我认为这可以解决问题...
我会使用关键帧动画。
让我们假设这是你的观点:
let val: [CGPoint] = [CGPoint(x:10, y:20), CGPoint(x:100, y:80), CGPoint(x:200, y:80), CGPoint(x:200, y:400), CGPoint(x:30, y:400), CGPoint(x:30, y:100)]
按下按钮后调用动画:
let duration = NSTimeInterval(2)
UIView.animateKeyframesWithDuration(duration, delay: 0.0, options: nil, animations: {
self.myView.center = CGPoint(x: 10, y: 20)
for (index, point) in enumerate(self.val) {
UIView.addKeyframeWithRelativeStartTime(Double(index) * 1.0 / Double(self.val.count), relativeDuration: 1.0 / Double(self.val.count), animations: {
self.myView.center = point
})
}
}, completion: nil)
当然您可以自定义动画持续时间、延迟等。
请记住
UIView.addKeyframeWithRelativeStartTime relativeDuration...
存在相对值,例如持续时间应介于 0-1 之间,其中 1 是您在
中指定的总持续时间
UIView.animateKeyframesWithDuration...
另一种方法是使用 animateWithDuration:delay:options:animations:completion: 并使用延迟参数为您提供移动之间所需的延迟时间。以下代码立即开始第一个动作,然后在一秒后开始每个后续动作。
Swift 2
class ViewController: UIViewController {
var block = UIView()
var pointArray = [CGPoint(x: 30, y: 30), CGPoint(x: 100, y: 30), CGPoint(x: 50, y: 300), CGPoint(x: 300, y: 170)]
var counter = 1
override func viewDidLoad() {
super.viewDidLoad()
block.frame = CGRect(origin: CGPointZero, size: CGSize(width: 50, height: 50))
block.center = pointArray[0]
block.backgroundColor = UIColor.redColor()
view.addSubview(block)
moveView()
}
func moveView() {
var delay = counter == 1 ? Double(0) : Double(1)
UIView.animateWithDuration(0.3, delay: delay, options: .CurveLinear, animations: { () -> Void in
self.block.center = self.pointArray[self.counter]
}) { (finished) -> Void in
self.counter++
if self.counter < self.pointArray.count {
self.moveView()
}
}
}
}
Swift 3, 4, 5
class ViewController: UIViewController {
var block = UIView()
var pointArray = [CGPoint(x: 30, y: 30), CGPoint(x: 100, y: 30), CGPoint(x: 50, y: 300), CGPoint(x: 300, y: 170)]
var counter = 1
override func viewDidLoad() {
super.viewDidLoad()
block.frame = CGRect(origin: CGPoint.zero, size: CGSize(width: 50, height: 50))
block.center = pointArray[0]
block.backgroundColor = UIColor.red
view.addSubview(block)
moveView()
}
func moveView() {
let delay = counter == 1 ? Double(0) : Double(1)
UIView.animate(withDuration: 0.3, delay: delay, options: .curveLinear, animations: { () -> Void in
self.block.center = self.pointArray[self.counter]
}) { (finished) -> Void in
self.counter+=1
if self.counter < self.pointArray.count {
self.moveView()
}
}
}
}
我正在制作一个应用程序,通过从数组中读取 CGPoint 并相应地设置图像的中心,以编程方式在屏幕上移动图像。最简单的形式是这样的:
for point in array {
image.center = point
sleep(1)
}
它发生在按下按钮之后,因此 for 循环位于按钮的 @IBAction func ...
内。
问题是屏幕在 image.center
更改后没有更新,而是在整个 for 循环完成后才更新,所以当图像位于数组的最后一个点时。如何强制更新视图?或者通常处理此问题的最佳方法是什么?
按照@matt 的建议移除睡眠,并尝试在图像的父视图上调用方法 layoutifneeded 而不是睡眠。视图需要重绘,所以我认为这可以解决问题...
我会使用关键帧动画。 让我们假设这是你的观点:
let val: [CGPoint] = [CGPoint(x:10, y:20), CGPoint(x:100, y:80), CGPoint(x:200, y:80), CGPoint(x:200, y:400), CGPoint(x:30, y:400), CGPoint(x:30, y:100)]
按下按钮后调用动画:
let duration = NSTimeInterval(2)
UIView.animateKeyframesWithDuration(duration, delay: 0.0, options: nil, animations: {
self.myView.center = CGPoint(x: 10, y: 20)
for (index, point) in enumerate(self.val) {
UIView.addKeyframeWithRelativeStartTime(Double(index) * 1.0 / Double(self.val.count), relativeDuration: 1.0 / Double(self.val.count), animations: {
self.myView.center = point
})
}
}, completion: nil)
当然您可以自定义动画持续时间、延迟等。 请记住
UIView.addKeyframeWithRelativeStartTime relativeDuration...
存在相对值,例如持续时间应介于 0-1 之间,其中 1 是您在
中指定的总持续时间UIView.animateKeyframesWithDuration...
另一种方法是使用 animateWithDuration:delay:options:animations:completion: 并使用延迟参数为您提供移动之间所需的延迟时间。以下代码立即开始第一个动作,然后在一秒后开始每个后续动作。
Swift 2
class ViewController: UIViewController {
var block = UIView()
var pointArray = [CGPoint(x: 30, y: 30), CGPoint(x: 100, y: 30), CGPoint(x: 50, y: 300), CGPoint(x: 300, y: 170)]
var counter = 1
override func viewDidLoad() {
super.viewDidLoad()
block.frame = CGRect(origin: CGPointZero, size: CGSize(width: 50, height: 50))
block.center = pointArray[0]
block.backgroundColor = UIColor.redColor()
view.addSubview(block)
moveView()
}
func moveView() {
var delay = counter == 1 ? Double(0) : Double(1)
UIView.animateWithDuration(0.3, delay: delay, options: .CurveLinear, animations: { () -> Void in
self.block.center = self.pointArray[self.counter]
}) { (finished) -> Void in
self.counter++
if self.counter < self.pointArray.count {
self.moveView()
}
}
}
}
Swift 3, 4, 5
class ViewController: UIViewController {
var block = UIView()
var pointArray = [CGPoint(x: 30, y: 30), CGPoint(x: 100, y: 30), CGPoint(x: 50, y: 300), CGPoint(x: 300, y: 170)]
var counter = 1
override func viewDidLoad() {
super.viewDidLoad()
block.frame = CGRect(origin: CGPoint.zero, size: CGSize(width: 50, height: 50))
block.center = pointArray[0]
block.backgroundColor = UIColor.red
view.addSubview(block)
moveView()
}
func moveView() {
let delay = counter == 1 ? Double(0) : Double(1)
UIView.animate(withDuration: 0.3, delay: delay, options: .curveLinear, animations: { () -> Void in
self.block.center = self.pointArray[self.counter]
}) { (finished) -> Void in
self.counter+=1
if self.counter < self.pointArray.count {
self.moveView()
}
}
}
}