长按(iconsContainerView
)之后,我正在显示一个小视图,但我不明白为什么handleLongPress(gesture:)
中的代码以这种方式执行。据我了解,它应该自上而下,每行应立即运行。意味着view.addSubview(iconsContainerView)
运行后,视图应显示在屏幕的左上方,因为其不透明度尚未设置为0。
因此,编写的代码(一旦手势开始)似乎视图将显示在屏幕的左上方,然后在变形后移动,然后消失(当不透明度设置为0时),然后当不透明度设置为1时,它会重新出现在动画中。但是发生的是,直到代码击中了动画块,视图才显示出来。
所以,一切都按我想要的方式工作–长按后,我确实希望子视图淡入。但是我只是想了解其背后的原因,以及为什么没有立即执行每行代码(或至少以这种方式显示在屏幕上)。它正在主线程上运行,我放入了断点并验证了这些行是否按顺序运行。
class ViewController: UIViewController {
let iconsContainerView: UIView = {
let containerView = UIView()
containerView.backgroundColor = .red
containerView.frame = CGRect(x: 0, y: 0, width: 200, height: 100)
return containerView
}()
override func viewDidLoad() {
super.viewDidLoad()
setUpLongPressGesture()
}
fileprivate func setUpLongPressGesture() {
view.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress)))
}
@objc func handleLongPress(gesture: UILongPressGestureRecognizer) {
print("Long gesture", Date())
if gesture.state == .began {
view.addSubview(iconsContainerView)
let pressedLocation = gesture.location(in: view)
let centeredX = (view.frame.width - iconsContainerView.frame.width) / 2
iconsContainerView.transform = CGAffineTransform(translationX: centeredX, y: pressedLocation.y - iconsContainerView.frame.height)
iconsContainerView.alpha = 0
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.iconsContainerView.alpha = 1
})
} else if gesture.state == .ended {
iconsContainerView.removeFromSuperview()
}
}
}
答案 0 :(得分:1)
我认为您期望您的代码像这样
you add a subview
system draws the view on the screen
you update the views transform
system redraws the view on the screen
you updates the views alpha
system redraws the view on the screen
由于您的代码在主线程上运行,并且系统绘图代码也在主线程上运行,因此它们都无法同时运行或在两者之间进行翻转。
实际发生的情况是,您的应用程序在后台运行着一个循环(RunLoop),该循环始终在运行。考虑它的最简单方法是
handles input
draws views to the screen
repeat
您的代码将属于handle input
部分。因此,您必须先完成整个方法的运行,然后循环才能移至将视图绘制到屏幕的下一步。这也是为什么不对主线程进行大量工作很重要的原因,如果您的方法要花一秒钟的时间来运行,那将意味着该应用程序无法在屏幕上绘制或在一秒钟内无法处理其他输入,这会使该应用似乎已冻结。
实际上,主运行循环中可能包含许多其他内容。它还有很多优化措施,以确保仅在需要时才运行,以避免不断运行cpu或在未发生任何更改而浪费电池寿命的情况下重新绘制。除非您开始直接与主运行循环进行交互或创建其他运行循环,否则这对于大多数iOS开发来说已经足够理解了,