I have a custom UIView subclass with UI designed in xib.
class MyView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
loadView()
commonInit()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadView()
commonInit()
}
func commonInit() {
let rightSwipeRecognizer = UISwipeGestureRecognizer(target: self, action: Selector("swipe"))
rightSwipeRecognizer.direction = .Right
dayInfoView.addGestureRecognizer(rightSwipeRecognizer)
}
func swipe() {
println("swiped")
}
private func loadView() {
let mainBundle = NSBundle.mainBundle()
let views = mainBundle.loadNibNamed("MyView", owner: self, options: nil)
let view = views.first as? UIView
addSubview(view!)
}
}
In my storyboard, I've added a view to VC and ensured that user interaction is enabled on that view. The result: no swipe handling
In case I add my view manually everything works fine:
override func viewDidLoad() {
super.viewDidLoad()
let myView = MyViewframe: CGRectMake(0, 300, 320, 200))
view.addSubview(myView)
}
What am I doing wrong?
Related
I'm trying to import from Xib full screen ScrollView into my ViewController.
Following that guide i've made many working examples of it, but when importing it from Xib, ScrollView not responding on scroll (not even bouncing)
My Xib View class:
class TestScroll: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
self.translatesAutoresizingMaskIntoConstraints = false
}
public static func getViewFromNib() -> TestScroll {
return UINib(nibName: "TestScroll", bundle: .main).instantiate(withOwner: nil, options: nil).first as! TestScroll
}
}
And this is how i adding it in ViewController:
override func viewDidLoad() {
super.viewDidLoad()
let testScroll = TestScroll.getViewFromNib()
self.view.addSubview(testScroll)
}
Please help, i've checked many guides already, but not found working example with Xib.
You need to set a frame / constraints
let testScroll = TestScroll.getViewFromNib()
testScroll.frame = self.view.bounds
self.view.addSubview(testScroll)
leave this
self.translatesAutoresizingMaskIntoConstraints = false
only if you'll set constraints
class MyClass {
let customView: MyView
init() {
customView = MyView()
customView.checkBox.addTarget(self, action: #selector(checkBoxValueChanged(_:)), for: .valueChanged)
}
#objc func checkBoxValueChanged(_ sender: M13Checkbox!) {
print("checkBoxValueChanged")
}
}
#IBDesignable class MyView: UIView {
#IBOutlet var view: UIView!
#IBOutlet var checkBox: M13Checkbox!
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
func setupView() {
let bundle = Bundle(for: type(of: self))
UINib(nibName: Constant.xib.MY_XIB, bundle: bundle).instantiate(withOwner: self, options: nil)
view.frame = bounds
view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
addSubview(view)
}
}
I want to manage an event in MyClass but the selector is not called.
If I do the same logic in UIViewController it works, but not in this case. Can anyone help me? Thanks
What is wrong with the following code, it's seems to have an endless loop. Initially comes through init:frame, to commonInit, but then the XIB loading line triggers entering again through init:coder etc.
Two areas of question:
a) How to instantiate probably to avoid this problem (i.e. want to use the XIB to layout, but then dynamically creating/position multiple of these on a parent view in code)
b) setting self.label.text is problematic as it seems self.label (a UILabel linked to the XIB) hasn't been setup at this point, hence is nil. So dynamically, when I want to create this little custom UIView via XIB, add it as a subclass, then immediately set a value of the label how do I do this?
import UIKit
class DirectionInfoView: UIView {
#IBOutlet weak var label: UILabel!
func commonInit() {
let viewName = "DirectionInfoView"
let view: DirectionInfoView = NSBundle.mainBundle().loadNibNamed(viewName, owner: self, options: nil).first as! DirectionInfoView // <== EXC_BAD_ACCESS (code=2...)
self.addSubview(view)
view.frame = self.bounds
self.label.text = "testing 123"
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
}
Usage:
let newInfoView = DirectionInfoView(frame: self.mapview.bounds)
myexitingView.addSubview(newInfoView)
This seems to work:
import UIKit
class DirectionInfoView: UIView {
#IBOutlet weak var label: UILabel!
func commonInit() {
self.layer.borderWidth = 5
self.layer.cornerRadius = 25
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
}
Usage:
let directionInfoView : DirectionInfoView = NSBundle.mainBundle().loadNibNamed("DirectionInfoView", owner: self, options: nil).first as! DirectionInfoView
mapview.addSubview(directionInfoView)
directionInfoView.label.text = "It Worked!"
I've created a UIView subclass, which i want to link to a xib file. I've added a xib file and set the class to DraggableView, however when i for instance create a lable and link it to the information. it returns that information is equal to nil? why doesnt it work?
class DraggableView: UIView {
var delegate: DraggableViewDelegate!
#IBOutlet var information: UILabel!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
information.text = "no info given"
information.textAlignment = NSTextAlignment.Center
information.textColor = UIColor.blackColor()
self.backgroundColor = UIColor.whiteColor()
}
}
Please ensure you add init from XIB method in your custom UIView like this:
class func instanceFromNib() -> UIView {
return UINib(nibName: "nib file name", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as UIView
}
And then you can use it like this:
var view = DraggableView.instanceFromNib()
view.information.text = "Test Label"
self.view.addSubview(view)
You need for your custom UIView to load XIB file first before setting objects value.
class DraggableView: UIView {
var delegate: DraggableViewDelegate!
#IBOutlet var information: UILabel!
init() { xibSetup() }
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
if self.subviews.count == 0 {
xibSetup()
}
}
func xibSetup() {
let view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
addSubview(view)
// INIT THERE YOUR LABEL
information.text = "no info given"
information.textAlignment = NSTextAlignment.Center
information.textColor = UIColor.blackColor()
self.backgroundColor = UIColor.whiteColor()
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "nib file name", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
and call simplely like that :
var view = DraggableView()
Something strange going on with IBOutlets.
In code I've try to access to this properties, but they are nil. Code:
class CustomKeyboard: UIView {
#IBOutlet var aButt: UIButton!
#IBOutlet var oButt: UIButton!
class func keyboard() -> UIView {
let nib = UINib(nibName: "CustomKeyboard", bundle: nil)
return nib.instantiateWithOwner(self, options: nil).first as UIView
}
override init() {
super.init()
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
// MARK: - Private
private func commonInit() {
println(aButt)
// aButt is nil
aButt = self.viewWithTag(1) as UIButton
println(aButt)
// aButt is not nil
}
}
That's expected, because the IBOutlet(s) are not assigned by the time the initializer is called.
Instead of calling commonInit() in init(coder:), do that in an override of awakeFromNib as follows:
// ...
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
commonInit()
}
// ...
Assuming you tried the standard troubleshooting steps for connecting IBOutlets, try this:
Apparently, you need to disable awake from nib in certain runtime cases.
override func awakeAfter(using aDecoder: NSCoder) -> Any? {
guard subviews.isEmpty else { return self }
return Bundle.main.loadNibNamed("MainNavbar", owner: nil, options: nil)?.first
}
Your nib may not be connected. My solution is quite simple. Somewhere in your project (I create a class called UIViewExtension.swift), add an extension of UIView with this handy connectNibUI method.
extension UIView {
func connectNibUI() {
let nib = UINib(nibName: String(describing: type(of: self)), bundle: nil).instantiate(withOwner: self, options: nil)
let nibView = nib.first as! UIView
nibView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(nibView)
//I am using SnapKit cocoapod for this method, to update constraints. You can use NSLayoutConstraints if you prefer.
nibView.snp.makeConstraints { (make) -> Void in
make.edges.equalTo(self)
}
}
}
Now you can call this method on any view, in your init method, do this:
override init(frame: CGRect) {
super.init(frame: frame)
connectNibUI()
}
Building on #ScottyBlades, I made this subclass:
class UIViewXib: UIView {
// I'm finding this necessary when I name a Xib-based UIView in IB. Otherwise, the IBOutlets are not loaded in awakeFromNib.
override func awakeAfter(using aDecoder: NSCoder) -> Any? {
guard subviews.isEmpty else { return self }
return Bundle.main.loadNibNamed(typeName(self), owner: nil, options: nil)?.first
}
}
func typeName(_ some: Any) -> String {
return (some is Any.Type) ? "\(some)" : "\(type(of: some))"
}
There is possibility that you not mentioned the FileOwner for xib.
Mention its class in File owner not in views Identity Inspector .
And how did you initiate your view from the controlller? Like this:
var view = CustomKeyboard.keyboard()
self.view.addSubview(view)