我想要子类UIView
,并显示一个类似登录的视图。这是我在Objective-C中创建的,但现在我想将它移植到Swift。我不使用故事板,所以我所有的UI都是用代码创建的。
但是第一个问题是我必须实现initWithCoder
。我给了它一个默认的实现,因为它不会被调用。现在,当我运行程序时,它崩溃了,因为我还必须实现initWithFrame
。现在我得到了这个:
override init() {
super.init()
println("Default init")
}
override init(frame: CGRect) {
super.init(frame: frame)
println("Frame init")
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
println("Coder init")
}
我的问题是我应该在哪里创建我的文本字段等。如果我从来没有实现过框架和编码器,我怎么“隐藏”它呢?
发布于 2014-11-21 16:39:10
我通常会做这样的事情,有点冗长。
class MyView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
addBehavior()
}
convenience init() {
self.init(frame: CGRect.zero)
}
required init(coder aDecoder: NSCoder) {
fatalError("This class does not support NSCoding")
}
func addBehavior() {
print("Add all the behavior here")
}
}
let u = MyView(frame: CGRect.zero)
let v = MyView()
(编辑:我已经对我的答案进行了编辑,以便初始化器之间的关系更加清晰)
发布于 2016-11-07 00:47:28
这更简单。
override init (frame : CGRect) {
super.init(frame : frame)
// Do what you want.
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
发布于 2017-01-30 11:49:15
自定义UIView子类示例
我通常不使用故事板或nib来创建iOS应用程序。我将分享我学到的一些技巧来回答你的问题。
隐藏不需要的init
方法
我的第一个建议是声明一个基本的UIView
来隐藏不需要的初始化器。我已经在my answer to "How to Hide Storyboard and Nib Specific Initializers in UI Subclasses"中详细讨论过这种方法。注意:这种方法假设你不会在故事板或nibs中使用BaseView
或它的后代,因为它会故意导致应用程序崩溃。
class BaseView: UIView {
// This initializer hides init(frame:) from subclasses
init() {
super.init(frame: CGRect.zero)
}
// This attribute hides `init(coder:)` from subclasses
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
}
您的自定义UIView子类应该继承自BaseView
。它必须在其初始值设定项中调用super.init()。它不需要实现init(coder:)
。下面的示例演示了这一点。
添加UITextField
我为在init
方法外部引用的子视图创建存储的属性。对于UITextField,我通常会这样做。我更喜欢在subview属性的声明中实例化子视图,如下所示:let textField = UITextField()
。
除非通过调用addSubview(_:)
将UITextField添加到自定义视图的子视图列表中,否则它将不可见。下面的示例演示了这一点。
不带自动布局的程序化布局
除非设置UITextField的大小和位置,否则它将不可见。我经常在layoutSubviews method中进行代码布局(不使用自动布局)。layoutSubviews()
在最初和每次发生调整大小事件时都会被调用。这允许根据CustomView的大小调整布局。例如,如果CustomView在各种大小的iPhones和iPads上显示全宽,并针对旋转进行调整,则它需要适应许多初始大小并动态调整大小。
您可以参考layoutSubviews()
中的frame.height
和frame.width
来获取CustomView的维度以供参考。下面的示例演示了这一点。
示例UIView子类
包含不需要实现init?(coder:)
的UITextField的自定义UIView子类。
class CustomView: BaseView {
let textField = UITextField()
override init() {
super.init()
// configure and add textField as subview
textField.placeholder = "placeholder text"
textField.font = UIFont.systemFont(ofSize: 12)
addSubview(textField)
}
override func layoutSubviews() {
super.layoutSubviews()
// Set textField size and position
textField.frame.size = CGSize(width: frame.width - 20, height: 30)
textField.frame.origin = CGPoint(x: 10, y: 10)
}
}
具有自动布局功能的程序化布局
您还可以在代码中使用Auto layout实现布局。因为我不经常这样做,所以我不会给出一个例子。您可以在Stack Overflow和Internet上的其他地方找到在代码中实现自动布局的示例。
程序化布局框架
有一些开源框架可以在代码中实现布局。我感兴趣但没有尝试过的是LayoutKit。它是由LinkedIn开发团队编写的。来自Github存储库:"LinkedIn创建了LayoutKit,因为我们发现自动布局对于可滚动视图中的复杂视图层次结构的性能不够好。“
为什么要把fatalError
放在init(coder:)
中
在创建永远不会在情节提要或nib中使用的UIView子类时,您可能会引入具有不同参数和初始化要求的初始化器,而这些参数和初始化要求无法由init(coder:)
方法调用。如果您没有使用fatalError
初始化(编码器:)失败,如果意外地在故事板/nib中使用,它可能会导致非常令人困惑的问题。fatalError断言这些意图。
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
如果你想在创建子类时运行一些代码,而不管它是在代码中创建的,还是在情节串连板/nib中创建的,那么你可以这样做(基于Jeff Gu Kang’s answer)。
class CustomView: UIView {
override init (frame: CGRect) {
super.init(frame: frame)
initCommon()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initCommon()
}
func initCommon() {
// Your custom initialization code
}
}
https://stackoverflow.com/questions/27056864
复制相似问题