ios - 是否可以以编程方式更新情节提要
问题描述
我用 UIView 子类创建了一个名为 Container 的类。
在 UIViewController 中,我使用了 Container 类的子类,我称之为 LoginContainer。
Container 类的代码是
@IBDesignable open class Container: UIView {
weak var controller: UIViewController!
var constraintsOK: Bool = false
@IBInspectable open var borderColor: UIColor = UIColor.clear {
didSet {
layer.borderColor = borderColor.cgColor
setNeedsLayout()
}
}
@IBInspectable open var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
setNeedsLayout()
}
}
@IBInspectable open var borderWidth: CGFloat = 1.0 {
didSet {
layer.borderWidth = borderWidth / UIScreen.main.scale
setNeedsLayout()
}
}
@IBInspectable open var shadow: Bool = false {
didSet {
if shadow {
addShadow()
setNeedsLayout()
}
}
}
// MARK: - Initializers
// IBDesignables require both of these inits, otherwise we'll get an error: IBDesignable View Rendering times out.
// http://stackoverflow.com/questions/26772729/ibdesignable-view-rendering-times-out
/// Pour les initializers, ne pas appeler customInit dans InterfaceBuilder
/// car déjà appelé dans PrepareforInterfaceBuilder
override public init(frame: CGRect) {
super.init(frame: frame)
#if !TARGET_INTERFACE_BUILDER
customInit()
#endif
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
#if !TARGET_INTERFACE_BUILDER
customInit()
#endif
}
// MARK: - Build control
override public func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
customInit()
}
/// Overriden method must call super.customInit().
open func customInit() {
addBorder()
/// L'ombre, s'il y en a est ajoutée dans layoutSubviews
}
/// Must be overriden when subclassed
open func setConstraints() {}
/// Adds a border to the control.
open func addBorder() {
layer.borderColor = borderColor.cgColor
layer.borderWidth = borderWidth / UIScreen.main.scale
// http://stackoverflow.com/questions/4735623/uilabel-layer-cornerradius-negatively-impacting-performance
if layer.shouldRasterize == false {
layer.masksToBounds = true
layer.rasterizationScale = UIScreen.main.scale
layer.shouldRasterize = true
}
}
open func addShadow() {
/// Attention, la couleur de fonds ne doit pas être à transparent, sinon on voit toute l'ombre en transparence
clipsToBounds = false
let shadowRect = CGRect(x: 10, y: 20, width: bounds.width-10, height: bounds.height-15)
layer.shadowColor = CGColor(red: 14/255, green: 47/255, blue: 133/255, alpha: 1)
layer.shadowOpacity = 1
layer.shadowPath = UIBezierPath(rect: shadowRect).cgPath
layer.shadowRadius = layer.cornerRadius
// https://www.hackingwithswift.com/example-code/uikit/how-to-add-a-shadow-to-a-uiview
layer.shadowPath = UIBezierPath(rect: shadowRect).cgPath
if layer.shouldRasterize == false {
layer.masksToBounds = false
layer.shouldRasterize = true
layer.rasterizationScale = UIScreen.main.scale
}
}
// MARK: - LifeCycle
override public func layoutSubviews() {
super.layoutSubviews()
if !constraintsOK {
setConstraints()
}
}
}
LoginContainer 子类的代码是
import UIKit
@IBDesignable class LoginContainer: Container {
override public func setConstraints() {
translatesAutoresizingMaskIntoConstraints = false
#if TARGET_INTERFACE_BUILDER
if let view = findViewController()?.view {
leftAnchor.constraint(equalTo: view.leftAnchor, constant: 10).isActive = true
topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
widthAnchor.constraint(equalToConstant: 100).isActive = true
heightAnchor.constraint(equalToConstant: 100).isActive = true
}
#endif
if let view = controller?.view {
leftAnchor.constraint(equalTo: view.leftAnchor, constant: 10).isActive = true
topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
widthAnchor.constraint(equalToConstant: 100).isActive = true
heightAnchor.constraint(equalToConstant: 100).isActive = true
}
constraintsOK = true
}
}
最后 UIViewController 的代码是
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var container: LoginContainer!
override func viewDidLoad() {
container.controller = self
super.viewDidLoad()
}
}
extension UIView {
public func findViewController() -> UIViewController? {
let nextResponder = self.next
if nextResponder is UIViewController {
return nextResponder as? UIViewController
} else if nextResponder is UIView {
return (nextResponder as! UIView).findViewController()
} else {
return nil
}
}
}
当我查看情节提要时,一切都正确,LoginContainer 的约束已正确更新
但是在情节提要中,我选择了 LoginContainer 视图,这就是我所看到的
LoginContainer 选择的链接不反映实际情况
如果 contentView 中包含多个容器视图,这可能会成为一个真正的问题(例如考虑键盘视图,其中每个键都由一个 Container 类表示)
所以我的问题是:是否可以通过程序更新情节提要,或者至少让 IB 在选择视图时显示正确的位置?
解决方案
推荐阅读
- android - 在 Android 中创建自定义 InputMask
- flutter - FileSystemException:操作系统错误:Google Pixel 3 中的权限被拒绝
- python - 递归因 None 对象而失败
- mysql - 将所有行分组为单行以获取 SQL 中的上下文数据
- python - s3fs read_block 与分隔符前瞻?
- angularjs - 产品价格页面上的角度变量在谷歌结构化工具上引发错误
- python - 如何在 python 3 中使用 pint Quantity 执行 numpy 矩阵乘法?
- c - 如何在 HAL 的中断模式下使用 PWM?
- python - 在任何窗口上钩住鼠标左键按下事件
- android-studio - 将 android 项目迁移到新的 android studio