Swift--XIB 嵌套不显示的问题

在Swift开发中遇到XIB嵌套后子视图不显示的困扰。通常做法是将MyView和SubView作为XIB拖入,但运行时SubView无法显示。解决方法涉及XibNestableView.Swift和NibLoadable.Swift两个文件,通过引入NibLoadable协议,改变视图加载方式,从而解决嵌套XIB的显示问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

进行xib作业的时候常常会出现xib嵌套不显示的问题,如下面草图所示: MyView是Xib拖出来的,SubView也同样是,MyView中的左侧Class:输入SubView,在SubView中左侧输入SubView,这符合一贯的思路,但是运行起来不会显示你的SubView,这就出现了嵌套Xib不显示的问题,解决思路:

1.在SubView.Xib文件中,右侧导航栏Class:不填,保持原来的类型,在Placeholder--File's Owner下修改Class:SubView
2.在SubView.Swift文件中 ,SubView遵守一个自己封装的协议XibNestableView,如下:class SubView: XibNestableView {},  初始化方法为:
required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

XibNestableView.Swift 拖入到工程文件中,文件内容为:

import UIKit
/// Xib 嵌套 Nib 所需继承的 View
class XibNestableView : UIView , NibLoadable {    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        if let view = UINib(nibName: String(describing: type(of: self)), bundle: nil).instantiate(withOwner: nil, options: nil)[0] as? UIView {
            view.equal(to: self)
        }
    }
}

NibLoadable.Swift文件拖入工程中,内容为:

import UIKit

/// 标志符协议
protocol NameIdentifierable {}

extension NameIdentifierable {
    /// 将类型名称作为标识符字符串
    static var identifier: String {
        return String(describing: self)
    }
}

/// 加载 Xib 协议
protocol NibLoadable: NameIdentifierable {}

extension NibLoadable where Self : AnyObject {
    /// 加载 Xib 中的 Nib 文件,Xib文件名称需与类型名称相同
    static var nib: UINib {
        return UINib(nibName: identifier, bundle: Bundle(for: self))
    }
}

extension NibLoadable where Self: UIView {
    
    /// 从 Nib 文件中加载 View
    ///
    /// - Returns: 实现 NibLoadable 的 UIView
    /// 例子: let view = UIView.loadFromNib()
    static func loadFromNib() -> Self {
        guard let view = nib.instantiate(withOwner: nil, options: nil).first as? Self else {
            fatalError("\(nib) Nib 文件的根视图需为 \(self) 类型")
        }
        return view
    }
}

protocol NibOwnerLoadable : NameIdentifierable {}

extension NibOwnerLoadable where Self : AnyObject {
    
    /// 加载 Xib 中的 Nib 文件,Xib文件名称需与类型名称相同
    static var nib: UINib {
        return UINib(nibName: identifier, bundle: Bundle(for: self))
    }
}

extension NibOwnerLoadable where Self: UIView {
    
    
    /// 加载 File’s Owner 中的内容
    /// 例子: required init?(coder aDecoder: NSCoder) {
    ///         super.init(coder: aDecoder)
    ///         self.loadNibContent()
    ///       }
    func loadNibContent() {
        let layoutAttributes: [NSLayoutConstraint.Attribute] = [.top, .leading, .bottom, .trailing]
        for case let view as UIView in Self.nib.instantiate(withOwner: self, options: nil) {
            view.translatesAutoresizingMaskIntoConstraints = false
            self.addSubview(view)
            NSLayoutConstraint.activate(layoutAttributes.map { attribute in
                NSLayoutConstraint(
                    item: view, attribute: attribute,
                    relatedBy: .equal,
                    toItem: self, attribute: attribute,
                    multiplier: 1, constant: 0.0
                )
            })
        }
    }
}

/// 加载 Storyboard 协议
protocol StoryboardLoadable {
    
    /// 需要加在的 Storyboard 的名字
    static var storyboardName: String? { get }
}

extension StoryboardLoadable where Self : AnyObject, Self : NameIdentifierable {
    
    /// 创建与 storyboardName 相同的 Storyboard, 若 storyboardName 为空则创建与当前类型名字相同的 Storyboard
    static var storyboard: UIStoryboard {
        return UIStoryboard(name: storyboardName ?? identifier, bundle: Bundle(for: self))
    }
}

/// Storyboard 中的控制器加载协议
protocol StoryboardSceneLoadable : NameIdentifierable {
   
    /// 需要提供目标 Storyboard, 可通过 StoryboardLoadable 协议创建
    static var storyboard: UIStoryboard { get }
}

extension StoryboardSceneLoadable {
    
    /// ViewController 的标志符
    static var sceneIdentifier: String {
        return identifier
    }
}

extension StoryboardSceneLoadable where Self: UIViewController {
    //
    /// 从 storyboard 中加载标志为 sceneIdentifier 的 ViewController
    ///
    /// - Returns: 标志为 sceneIdentifier 的 ViewController
    static func instantiate() -> Self {
        let storyboard = Self.storyboard
        let viewController = storyboard.instantiateViewController(withIdentifier: self.sceneIdentifier)
        guard let typedViewController = viewController as? Self else {
            fatalError("\(storyboard) 中的 '\(self.sceneIdentifier)'控制器不是 '\(self)' 类型")
        }
        return typedViewController
    }
}

NibLoadable.Swift 协议的作用是将创建View由原来的方式:

let alertView = Bundle.main.loadNibNamed("BatchCloseAlertView", owner: vc, options: nil)?.first as! BatchCloseAlertView

修改为:

let alertView = BatchCloseAlertView.loadFromNib()

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值