如何检测 swift ios xcode 中 UIView 大小何时更改?
How to detect when UIView size is changed in swift ios xcode?
我正在使用 UIScrollView 中的 CATiledLayer 尝试一些东西。
不知何故,UIScrollView 中的UIView 的大小变大了。我需要确切地找出导致此调整大小的原因。
Is there a way to detect when the size of UIView(either frame, bounds) or the contentSize of UIScrollView is resized?
我试过了
override var frame: CGRect {
didSet {
println("frame changed");
}
}
在 UIView 子类中,
但它只在应用程序启动时调用一次,尽管 UIView 的大小随后会调整。
只要边界发生变化,就会调用 viewWillLayoutSubviews()
和 viewDidLayoutSubviews()
。在视图控制器中。
答案是正确的,尽管就我而言,我在情节提要中设置的约束导致 UIView 大小发生变化而没有回调任何检测函数。
你也可以使用 KVO:
您可以像这样设置 KVO,其中 view
是您要观察帧变化的 view
:
self.addObserver(view, forKeyPath: "center", options: NSKeyValueObservingOptions.New, context: nil)
您可以通过此通知获取更改:
override func observeValueForKeyPath(keyPath: String!, ofObject object: AnyObject!, change: NSDictionary!, context: CMutableVoidPointer) {
}
只要您正在观察的视图的框架发生变化,就会调用 observeValueForKeyPath
。
还记得在你的视图即将被释放时移除观察者:
view.removeObserver(self, forKeyPath:"center")
步骤1:viewWillLayoutSubviews
Called to notify the view controller that its view is about to
layout its subviews
When a view's bounds change, the view adjusts the position of its
subviews. Your view controller can override this method to make
changes before the view lays out its subviews. The default
implementation of this method does nothing.
步骤2:viewDidLayoutSubviews
Called to notify the view controller that its view has just laid out
its subviews.
When the bounds change for a view controller's view, the view
adjusts the positions of its subviews and then the system calls this
method. However, this method being called does not indicate that the
individual layouts of the view's subviews have been adjusted. Each
subview is responsible for adjusting its own layout.
Your view controller can override this method to make changes after
the view lays out its subviews. The default implementation of this
method does nothing.
每当 UIView 的边界 改变时,就会调用以上这些方法
这里有答案:
只需将其粘贴到方法主体之外即可:
override var bounds: CGRect {
didSet {
// Do stuff here
}
}
您可以创建自定义 class,并使用闭包轻松获取更新后的矩形。在处理 classes 时特别方便(比如 CAGradientLayer
希望你给他们一个 CGRect
):
GView.swift
:
import Foundation
import UIKit
class GView: UIView {
var onFrameUpdated: ((_ bounds: CGRect) -> Void)?
override func layoutSublayers(of layer: CALayer) {
super.layoutSublayers(of: layer)
self.onFrameUpdated?(self.bounds)
}
}
用法示例:
let headerView = GView()
let gradientLayer = CAGradientLayer()
headerView.layer.insertSublayer(gradientLayer, at: 0)
gradientLayer.colors = [
UIColor.mainColorDark.cgColor,
UIColor.mainColor.cgColor,
]
gradientLayer.locations = [
0.0,
1.0,
]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
headerView.onFrameUpdated = { _ in // here you have access to `bounds` and `frame` with proper values
gradientLayer.frame = headerView.bounds
}
如果您不是通过代码添加视图,您可以将 Storyboard 中的自定义 Class 属性 设置为 GView
。
请注意,名称 GView
被选为公司衡量标准,可能选择 FrameObserverView
这样的名称会更好。
对于 UIViews,就像:
override func layoutSubviews() {
super.layoutSubviews()
setupYourNewLayoutHereMate()
}
您可以使用 FrameObserver 广告连播。
它没有使用 KVO 或 Method Swizzling,因此即使 UIKit
的底层实现发生变化也不会破坏您的代码。
whateverUIViewSubclass.addFrameObserver { frame, bounds in // get updates when the size of view changes
print("frame", frame, "bounds", bounds)
}
您可以在 UIView
实例或其任何子类上调用它,例如 UILabel
、UIButton
、UIStackView
等
这是一个简单且不太hacky的解决方案:记住视图的最后大小,在重写的layoutSubviews
方法中将其与新大小进行比较,然后在确定后执行某些操作尺寸变了。
/// Create this as a private property in your UIView subclass
private var lastSize: CGSize = .zero
open override func layoutSubviews() {
// First call super to let the system update the layout
super.layoutSubviews()
// Check if:
// 1. The view is part of the view hierarchy
// 2. Our lastSize var doesn't still have its initial value
// 3. The new size is different from the last size
if self.window != nil, lastSize != .zero, frame.size != lastSize {
// React to the size change
}
lastSize = frame.size
}
请注意,您不必包含 self.window != nil
检查,但我假设在大多数情况下,您只对了解作为视图层次结构一部分的视图的大小更改感兴趣。
另请注意,如果您想在最初显示视图时获知第一次大小更改,则可以删除 lastSize != .zero
检查。通常我们对该事件不感兴趣,而只对由于设备旋转或特征集合更改而导致的后续大小变化感兴趣。
尽情享受吧!
我正在使用 UIScrollView 中的 CATiledLayer 尝试一些东西。
不知何故,UIScrollView 中的UIView 的大小变大了。我需要确切地找出导致此调整大小的原因。
Is there a way to detect when the size of UIView(either frame, bounds) or the contentSize of UIScrollView is resized?
我试过了
override var frame: CGRect {
didSet {
println("frame changed");
}
}
在 UIView 子类中,
但它只在应用程序启动时调用一次,尽管 UIView 的大小随后会调整。
viewWillLayoutSubviews()
和 viewDidLayoutSubviews()
。在视图控制器中。
答案是正确的,尽管就我而言,我在情节提要中设置的约束导致 UIView 大小发生变化而没有回调任何检测函数。
你也可以使用 KVO:
您可以像这样设置 KVO,其中 view
是您要观察帧变化的 view
:
self.addObserver(view, forKeyPath: "center", options: NSKeyValueObservingOptions.New, context: nil)
您可以通过此通知获取更改:
override func observeValueForKeyPath(keyPath: String!, ofObject object: AnyObject!, change: NSDictionary!, context: CMutableVoidPointer) {
}
只要您正在观察的视图的框架发生变化,就会调用 observeValueForKeyPath
。
还记得在你的视图即将被释放时移除观察者:
view.removeObserver(self, forKeyPath:"center")
步骤1:viewWillLayoutSubviews
Called to notify the view controller that its view is about to layout its subviews
When a view's bounds change, the view adjusts the position of its subviews. Your view controller can override this method to make changes before the view lays out its subviews. The default implementation of this method does nothing.
步骤2:viewDidLayoutSubviews
Called to notify the view controller that its view has just laid out its subviews.
When the bounds change for a view controller's view, the view adjusts the positions of its subviews and then the system calls this method. However, this method being called does not indicate that the individual layouts of the view's subviews have been adjusted. Each subview is responsible for adjusting its own layout.
Your view controller can override this method to make changes after the view lays out its subviews. The default implementation of this method does nothing.
每当 UIView 的边界 改变时,就会调用以上这些方法
这里有答案:
只需将其粘贴到方法主体之外即可:
override var bounds: CGRect {
didSet {
// Do stuff here
}
}
您可以创建自定义 class,并使用闭包轻松获取更新后的矩形。在处理 classes 时特别方便(比如 CAGradientLayer
希望你给他们一个 CGRect
):
GView.swift
:
import Foundation
import UIKit
class GView: UIView {
var onFrameUpdated: ((_ bounds: CGRect) -> Void)?
override func layoutSublayers(of layer: CALayer) {
super.layoutSublayers(of: layer)
self.onFrameUpdated?(self.bounds)
}
}
用法示例:
let headerView = GView()
let gradientLayer = CAGradientLayer()
headerView.layer.insertSublayer(gradientLayer, at: 0)
gradientLayer.colors = [
UIColor.mainColorDark.cgColor,
UIColor.mainColor.cgColor,
]
gradientLayer.locations = [
0.0,
1.0,
]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
headerView.onFrameUpdated = { _ in // here you have access to `bounds` and `frame` with proper values
gradientLayer.frame = headerView.bounds
}
如果您不是通过代码添加视图,您可以将 Storyboard 中的自定义 Class 属性 设置为 GView
。
请注意,名称 GView
被选为公司衡量标准,可能选择 FrameObserverView
这样的名称会更好。
对于 UIViews,就像:
override func layoutSubviews() {
super.layoutSubviews()
setupYourNewLayoutHereMate()
}
您可以使用 FrameObserver 广告连播。
它没有使用 KVO 或 Method Swizzling,因此即使 UIKit
的底层实现发生变化也不会破坏您的代码。
whateverUIViewSubclass.addFrameObserver { frame, bounds in // get updates when the size of view changes
print("frame", frame, "bounds", bounds)
}
您可以在 UIView
实例或其任何子类上调用它,例如 UILabel
、UIButton
、UIStackView
等
这是一个简单且不太hacky的解决方案:记住视图的最后大小,在重写的layoutSubviews
方法中将其与新大小进行比较,然后在确定后执行某些操作尺寸变了。
/// Create this as a private property in your UIView subclass
private var lastSize: CGSize = .zero
open override func layoutSubviews() {
// First call super to let the system update the layout
super.layoutSubviews()
// Check if:
// 1. The view is part of the view hierarchy
// 2. Our lastSize var doesn't still have its initial value
// 3. The new size is different from the last size
if self.window != nil, lastSize != .zero, frame.size != lastSize {
// React to the size change
}
lastSize = frame.size
}
请注意,您不必包含 self.window != nil
检查,但我假设在大多数情况下,您只对了解作为视图层次结构一部分的视图的大小更改感兴趣。
另请注意,如果您想在最初显示视图时获知第一次大小更改,则可以删除 lastSize != .zero
检查。通常我们对该事件不感兴趣,而只对由于设备旋转或特征集合更改而导致的后续大小变化感兴趣。
尽情享受吧!