从 XIB 加载视图作为滚动视图的子视图
Load view from XIB as a subview of a scrollview
我还是个 SO 和 Swift 新手,所以请耐心等待并跳过这个问题:-)
在 XIB
的 awakeFromNib
的正文中,我想加载一些视图作为 UIScrollView
的子视图(基本上,XIB
包含一个滚动视图、标签和按钮)。
如果在一个循环中加载动态创建的视图,滚动视图将完美运行,例如。
let customView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 150))
customView.frame = CGRect(x: i*300 , y: 0, width: 300, height: 150)
customView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(customView)
但我有不同的目标。
在另一个 XIB
中,我有一个图像视图和一个带有一些标签的堆栈视图。此 XIB
在故事板中连接到扩展 UIView
.
的 class SingleEvent
我想执行以下操作:
- 使用
XIB
作为一种 "blueprint" 并在我的滚动视图中多次加载相同的视图;
- 向任何实例传递一些数据;
这可能吗?
我试过这样加载 XIB 的内容:
let customView = Bundle.main.loadNibNamed("SingleEvent", owner: self, options: nil)?.first as? SingleEvent
这样:
let customView = SingleEvent()
第一个使应用程序崩溃,而第二个没有导致任何问题,但我看不到任何效果(它不加载任何内容)。
我最新的SingleEvent
内容如下:
import UIKit
class SingleEvent: UIView {
@IBOutlet weak var label:UILabel!
@IBOutlet weak var imageView:UIImageView!
override init(frame: CGRect) {
super.init(frame: frame)
loadViewFromNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadViewFromNib()
}
func loadViewFromNib() -> UIView {
let myView = Bundle.main.loadNibNamed("SingleEvent", owner: self, options: nil)?.first as! UIView
return myView
}
}
提前致谢,如有任何帮助,我们将不胜感激:-)
好的,我明白了。问题可能实际上是来自 xib 的 loadViewFromNib 函数 return UIView,但您没有以任何方式使用它。
让我们试试这个方法:
1) 使您的 loadViewFromNib 函数静态
// Return our SingleEvent instance here
static func loadViewFromNib() -> SingleEvent {
let myView = Bundle.main.loadNibNamed("SingleEvent", owner: self, options: nil)?.first as! SingleEvent
return myView
}
2) 删除 SingleEvent 中的所有 inits class
3) 在需要的地方初始化它:
let customView = SingleView.loadViewFromNib()
要在视图内部传递数据,您可以在 SingleView 中创建新函数 class:
func configureView(with dataModel:DataModel) {
//Set data to IBOutlets here
}
然后像这样从外部使用它:
let customView = SingleView.loadViewFromNib()
let dataModel = DataModel()
customView.configureView(with: dataModel)
有多种方法可以从 xibs 加载自定义视图(classes)。您可能会发现此方法更简单一些。
首先,像这样创建你的 xib:
请注意,File's Owner
的 Class 是默认值 (NSObject
)。
相反,将您的自定义 class 分配给 xib 中的 "root" 视图:
现在,我们的整个自定义视图 class 看起来像这样:
class SingleEvent: UIView {
@IBOutlet var topLabel: UILabel!
@IBOutlet var middleLabel: UILabel!
@IBOutlet var bottomLabel: UILabel!
@IBOutlet var imageView: UIImageView!
}
并且,我们没有将 loadNibNamed(...)
放入我们的自定义 class 中,而是创建了一个 UIView
扩展:
extension UIView {
class func fromNib<T: UIView>() -> T {
return Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, options: nil)![0] as! T
}
}
要加载和使用我们的自定义 class,我们可以这样做:
class FromXIBViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// create an instance of SingleEvent from its xib/nib
let v = UIView.fromNib() as SingleEvent
// we're going to use auto-layout & constraints
v.translatesAutoresizingMaskIntoConstraints = false
// set the text of the labels
v.topLabel?.text = "Top Label"
v.middleLabel?.text = "Middle Label"
v.bottomLabel?.text = "Bottom Label"
// set the image
v.imageView.image = UIImage(named: "myImage")
// add the SingleEvent view
view.addSubview(v)
// constrain it 200 x 200, centered X & Y
NSLayoutConstraint.activate([
v.widthAnchor.constraint(equalToConstant: 200.0),
v.heightAnchor.constraint(equalToConstant: 200.0),
v.centerXAnchor.constraint(equalTo: view.centerXAnchor),
v.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
}
结果为:
还有...这里是加载 10 个 SingleEvent
视图实例并将它们添加到垂直滚动视图的示例:
class FromXIBViewController: UIViewController {
var theScrollView: UIScrollView = {
let v = UIScrollView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .cyan
return v
}()
var theStackView: UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .vertical
v.alignment = .fill
v.distribution = .fill
v.spacing = 20.0
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
// add the scroll view to the view
view.addSubview(theScrollView)
// constrain it 40-pts on each side
NSLayoutConstraint.activate([
theScrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40.0),
theScrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -40.0),
theScrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 40.0),
theScrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -40.0),
])
// add a stack view to the scroll view
theScrollView.addSubview(theStackView)
// constrain it 20-pts on each side
NSLayoutConstraint.activate([
theStackView.topAnchor.constraint(equalTo: theScrollView.topAnchor, constant: 20.0),
theStackView.bottomAnchor.constraint(equalTo: theScrollView.bottomAnchor, constant: -20.0),
theStackView.leadingAnchor.constraint(equalTo: theScrollView.leadingAnchor, constant: 20.0),
theStackView.trailingAnchor.constraint(equalTo: theScrollView.trailingAnchor, constant: -20.0),
// stackView width = scrollView width -40 (20-pts padding on left & right
theStackView.widthAnchor.constraint(equalTo: theScrollView.widthAnchor, constant: -40.0),
])
for i in 0..<10 {
// create an instance of SingleEvent from its xib/nib
let v = UIView.fromNib() as SingleEvent
// we're going to use auto-layout & constraints
v.translatesAutoresizingMaskIntoConstraints = false
// set the text of the labels
v.topLabel?.text = "Top Label: \(i)"
v.middleLabel?.text = "Middle Label: \(i)"
v.bottomLabel?.text = "Bottom Label: \(i)"
// set the image (assuming we have images named myImage0 thru myImage9
v.imageView.image = UIImage(named: "myImage\(i)")
theStackView.addArrangedSubview(v)
}
}
}
结果:
我还是个 SO 和 Swift 新手,所以请耐心等待并跳过这个问题:-)
在 XIB
的 awakeFromNib
的正文中,我想加载一些视图作为 UIScrollView
的子视图(基本上,XIB
包含一个滚动视图、标签和按钮)。
如果在一个循环中加载动态创建的视图,滚动视图将完美运行,例如。
let customView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 150))
customView.frame = CGRect(x: i*300 , y: 0, width: 300, height: 150)
customView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(customView)
但我有不同的目标。
在另一个 XIB
中,我有一个图像视图和一个带有一些标签的堆栈视图。此 XIB
在故事板中连接到扩展 UIView
.
SingleEvent
我想执行以下操作:
- 使用
XIB
作为一种 "blueprint" 并在我的滚动视图中多次加载相同的视图; - 向任何实例传递一些数据;
这可能吗?
我试过这样加载 XIB 的内容:
let customView = Bundle.main.loadNibNamed("SingleEvent", owner: self, options: nil)?.first as? SingleEvent
这样:
let customView = SingleEvent()
第一个使应用程序崩溃,而第二个没有导致任何问题,但我看不到任何效果(它不加载任何内容)。
我最新的SingleEvent
内容如下:
import UIKit
class SingleEvent: UIView {
@IBOutlet weak var label:UILabel!
@IBOutlet weak var imageView:UIImageView!
override init(frame: CGRect) {
super.init(frame: frame)
loadViewFromNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadViewFromNib()
}
func loadViewFromNib() -> UIView {
let myView = Bundle.main.loadNibNamed("SingleEvent", owner: self, options: nil)?.first as! UIView
return myView
}
}
提前致谢,如有任何帮助,我们将不胜感激:-)
好的,我明白了。问题可能实际上是来自 xib 的 loadViewFromNib 函数 return UIView,但您没有以任何方式使用它。
让我们试试这个方法:
1) 使您的 loadViewFromNib 函数静态
// Return our SingleEvent instance here
static func loadViewFromNib() -> SingleEvent {
let myView = Bundle.main.loadNibNamed("SingleEvent", owner: self, options: nil)?.first as! SingleEvent
return myView
}
2) 删除 SingleEvent 中的所有 inits class
3) 在需要的地方初始化它:
let customView = SingleView.loadViewFromNib()
要在视图内部传递数据,您可以在 SingleView 中创建新函数 class:
func configureView(with dataModel:DataModel) {
//Set data to IBOutlets here
}
然后像这样从外部使用它:
let customView = SingleView.loadViewFromNib()
let dataModel = DataModel()
customView.configureView(with: dataModel)
有多种方法可以从 xibs 加载自定义视图(classes)。您可能会发现此方法更简单一些。
首先,像这样创建你的 xib:
请注意,File's Owner
的 Class 是默认值 (NSObject
)。
相反,将您的自定义 class 分配给 xib 中的 "root" 视图:
现在,我们的整个自定义视图 class 看起来像这样:
class SingleEvent: UIView {
@IBOutlet var topLabel: UILabel!
@IBOutlet var middleLabel: UILabel!
@IBOutlet var bottomLabel: UILabel!
@IBOutlet var imageView: UIImageView!
}
并且,我们没有将 loadNibNamed(...)
放入我们的自定义 class 中,而是创建了一个 UIView
扩展:
extension UIView {
class func fromNib<T: UIView>() -> T {
return Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, options: nil)![0] as! T
}
}
要加载和使用我们的自定义 class,我们可以这样做:
class FromXIBViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// create an instance of SingleEvent from its xib/nib
let v = UIView.fromNib() as SingleEvent
// we're going to use auto-layout & constraints
v.translatesAutoresizingMaskIntoConstraints = false
// set the text of the labels
v.topLabel?.text = "Top Label"
v.middleLabel?.text = "Middle Label"
v.bottomLabel?.text = "Bottom Label"
// set the image
v.imageView.image = UIImage(named: "myImage")
// add the SingleEvent view
view.addSubview(v)
// constrain it 200 x 200, centered X & Y
NSLayoutConstraint.activate([
v.widthAnchor.constraint(equalToConstant: 200.0),
v.heightAnchor.constraint(equalToConstant: 200.0),
v.centerXAnchor.constraint(equalTo: view.centerXAnchor),
v.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
}
结果为:
还有...这里是加载 10 个 SingleEvent
视图实例并将它们添加到垂直滚动视图的示例:
class FromXIBViewController: UIViewController {
var theScrollView: UIScrollView = {
let v = UIScrollView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .cyan
return v
}()
var theStackView: UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .vertical
v.alignment = .fill
v.distribution = .fill
v.spacing = 20.0
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
// add the scroll view to the view
view.addSubview(theScrollView)
// constrain it 40-pts on each side
NSLayoutConstraint.activate([
theScrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40.0),
theScrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -40.0),
theScrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 40.0),
theScrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -40.0),
])
// add a stack view to the scroll view
theScrollView.addSubview(theStackView)
// constrain it 20-pts on each side
NSLayoutConstraint.activate([
theStackView.topAnchor.constraint(equalTo: theScrollView.topAnchor, constant: 20.0),
theStackView.bottomAnchor.constraint(equalTo: theScrollView.bottomAnchor, constant: -20.0),
theStackView.leadingAnchor.constraint(equalTo: theScrollView.leadingAnchor, constant: 20.0),
theStackView.trailingAnchor.constraint(equalTo: theScrollView.trailingAnchor, constant: -20.0),
// stackView width = scrollView width -40 (20-pts padding on left & right
theStackView.widthAnchor.constraint(equalTo: theScrollView.widthAnchor, constant: -40.0),
])
for i in 0..<10 {
// create an instance of SingleEvent from its xib/nib
let v = UIView.fromNib() as SingleEvent
// we're going to use auto-layout & constraints
v.translatesAutoresizingMaskIntoConstraints = false
// set the text of the labels
v.topLabel?.text = "Top Label: \(i)"
v.middleLabel?.text = "Middle Label: \(i)"
v.bottomLabel?.text = "Bottom Label: \(i)"
// set the image (assuming we have images named myImage0 thru myImage9
v.imageView.image = UIImage(named: "myImage\(i)")
theStackView.addArrangedSubview(v)
}
}
}
结果: