I have created UIView in storyboard (Xcode 8.2.1). I reference the things inside to UIView class name LoginView. I delete one things by mistake then I got error at the line of Bundle.main.loadNibNamed("LoginView", owner: self, options: nil). EXC_BAD_ACCESS(code=2,....) I read about this in some answer here, they said about referencing missing. I try to reference everything again but still error. I'm now confusing about what should I reference it to. File Owner or View.
EDIT : The bug is happen when this View is render.
LoginView.swift
import UIKit
class LoginView: UIView {
#IBOutlet var view: UIView!
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
#IBOutlet weak var forgotPasswordBtn: UIButton!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
Bundle.main.loadNibNamed("LoginView", owner: self, options: nil)
self.addSubview(view)
view.frame = self.bounds
emailField.becomeFirstResponder()
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIInputViewController.dismissKeyboard))
view.addGestureRecognizer(tap)
}
func dismissKeyboard() {
view.endEditing(true)
}
}
This is my components in LoginView StoryBoard
And this is my referencing.
There's a CocoaPod called NibDesignable that not only configures the nib into the view (with constraints), but also makes the view IBDesignable so you can see your nib-based-views in the storyboard.
NibDesignable requires you to change the nib's file owner to the view class rather than the nib's view's custom class. Also, outlet connections must be made from the file's owner and not from the nib's view.
#IBDesignable class LoginView: NibDesignable {
// MARK: Outlets
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
#IBOutlet weak var forgotPasswordBtn: UIButton!
// MARK: Properties
var tap: UITapGestureRecognizer? {
willSet {
tap.flatMap { removeGestureRecognizer($0) }
}
didSet {
tap.flatMap { addGestureRecognizer($0) }
}
}
// MARK: Lifecycle
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
tap = UITapGestureRecognizer(
target: self,
action: #selector(didRecognizeTapGesture)
)
emailField.becomeFirstResponder()
}
// MARK: Actions
#IBAction func didRecognizeTapGesture() {
endEditing(true)
}
}
Related
I have created a XIB for UIView named popUpView.xib and a swift file associated with it popUpView.swift
My popUpView.swift code is like this:
#objc class popUpView: UIView {
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var mobileNumberTF: UITextField!
#IBOutlet weak var customerIdTF: UITextField!
#IBOutlet weak var panNumberTF: UITextField!
#IBOutlet weak var cancelBtn: UIButton!
#IBOutlet weak var saveBtn: UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
self.initSubViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.initSubViews()
}
func initSubViews() {
let name = String(describing: type(of: self))
let nib = UINib(nibName: name, bundle: .main)
nib.instantiate(withOwner: self, options: nil)
self.addSubview(self.containerView)
self.containerView.translatesAutoresizingMaskIntoConstraints = false
self.addConstraints()
}
func addConstraints() {
NSLayoutConstraint.activate([
self.topAnchor.constraint(equalTo: containerView.topAnchor),
self.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
self.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
self.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
])
}
}
Now I am trying to load this view as a popUp in my ViewController written in Objective-C
In my ViewController, I am calling like this:
-(void)showPopUpView {
popUpView *popUpView = [[popUpView alloc] initWithFrame:CGRectZero];
[self.view addSubview:popUpView];
[popUpView.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:25].active = YES;
[popUpView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:25].active = YES;
[popUpView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:25].active = YES;
[popUpView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:25].active = YES;
}
In viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
[self showPopUpView];
}
I think I might be doing it the wrong way. What is the right way to load this custom view programatically in Obj-C?
I got curious since the last time I did this, so I created a project to test it out. This is how it works for me.
My xib:
My PopupView.m
My ViewController.m
Added the code to this GitHub repo:
https://github.com/ArunEA/ObjcViewWithNib
I have set the file owner to be UserBannerView.
The UIView in the storyboard that uses this .xib file is also set to be UserBannerView.
I am not getting any errors, yet it won't show up in either the simulator or the storyboard.
import UIKit
#IBDesignable class UserBannerView: UIView {
var view: UIView!
#IBOutlet weak var userCreditsLabel: UILabel!
#IBOutlet weak var userRenewDateLabel: UILabel!
#IBOutlet weak var userImage: circlePP!
#IBOutlet weak var userMembershipBtn: UIButton!
#IBOutlet weak var userNameLabel: UILabel!
var nibName:String = "UserBannerView"
public override init(frame:CGRect){
super.init(frame: frame)
print("UserBannerView init from frame")
setup()
}
public required init?(coder aDecoder:NSCoder){
super.init(coder: aDecoder)
print("UserBannerView init from decode")
setup()
}
override func awakeFromNib() {
print("UserBannerView awakeFromNib")
// setup()
}
func setup() {
print("UserBannerView:setup")
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "UserBannerView", bundle: bundle)
self.view = nib.instantiate(withOwner: self, options: nil).first as! UIView
self.view.frame = bounds
self.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.addSubview(self.view)
}
}
Try implementing your awakeFromNib method and add prepareForInterfaceBuilder method
override func awakeFromNib() {
super.awakeFromNib()
self.setup()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setup()
}
Also make sure that your class is setted as fileOwner in your xib file
Hope this helps
I have been trying to figure this out for days and haven't had much luck :(
What I want to do is set the variable inside of an instance of a XIB (called BottomNav) that already exists in another ViewController, called "curX". I have come the closest with the following:
class Util: NSObject {
class func loadNib() {
let nib: BottomNav = Bundle.main.loadNibNamed("BottomNav", owner: self, options: nil)!.first as! BottomNav
nib.curX = 10
}
}
Here is the BottomNav Class:
class BottomNav: UIView {
#IBOutlet var view: UIView!
#IBOutlet weak var homeBtn: UIView!
#IBOutlet weak var scroller: UIScrollView!
#IBOutlet weak var scrollerContent: UIView!
var curX = 32
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
Bundle.main.loadNibNamed("BottomNav", owner: self, options: nil)
self.addSubview(self.view)
}
}
This passes the compiler with no warnings, but when it's ran I get a "this class is not key value coding-compliant for the key" error. This usually appears when there's an outlet that no longer exists, but this is definitely not the case, I've tested it with multiple XIBs that are already on the app, and had no problem loading in the first place via storyboards. I only get this error with "loadNibNamed".
Am I even on the right path here? My thought is maybe my Util class doesn't have access to Bundle or something?
class BottomNav: UIView {
#IBOutlet var view: UIView!
#IBOutlet weak var homeBtn: UIView!
#IBOutlet weak var scroller: UIScrollView!
#IBOutlet weak var scrollerContent: UIView!
var curX = 32
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit(){
Bundle.main.loadNibNamed("BottomNav", owner: self, options: nil)
guard let content = view else { return }
content.frame = self.bounds
content.autoresizingMask = [.flexibleHeight, .flexibleWidth]
self.addSubview(content)
}
}
And when calling the instance, try the following.
let instance = BottomNav()
instance.curX = 30
Swift 3.0
I Think you get you solution from this. All the best
var view: UIView!
override init(frame: CGRect) {
// call super.init(frame:)
super.init(frame: frame)
// 3. Setup view from .xib file
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
// call super.init(coder:)
super.init(coder: aDecoder)
// 3. Setup view from .xib file
xibSetup()
}
// MARK: - UI setup
func xibSetup() {
let nib = UINib(nibName: "BottomNav", bundle: nil)
view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
// use bounds not frame or it'll be offset
view.frame = bounds
// Make the view stretch with containing view
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
addSubview(view)
}
So I have a custom UIView with a button in it, called the home button. In other view controllers, this home button within this particular UIView works just fine. In one particular view controller, however, the home button is non responsive to touches- the app acts as though the button is not even there.
class TemplateChooserViewController: UIViewController, HeaderViewDelegate {
...
#IBOutlet weak var myHeader: HeaderView!
override func viewDidLoad() {
super.viewDidLoad()
myHeader.delegate = self
myHeader.Title.text = "Template Chooser"
... //All the rest of this function has been commented out and the home button still didn't work
}
func homeButtonTapped()
{
let home = self.navigationController?.viewControllers.first //code never reaches here
self.navigationController?.popToViewController(home!, animated: false)
}
And the HeaderView file looks like:
protocol HeaderViewDelegate: class {
func homeButtonTapped()
func informationButtonTapped()
}
class HeaderView: UIView {
weak var delegate: HeaderViewDelegate?
#IBOutlet var view: UIView!
#IBOutlet weak var Title: UILabel!
#IBOutlet weak var flameDecal: UIImageView!
#IBOutlet weak var homeButton: UIButton!
required init(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)!
Bundle.main.loadNibNamed("HeaderView", owner: self, options: nil)
self.addSubview(self.view)
}
#IBAction func homeButtonTouched(_ sender: UIButton)
{
delegate?.homeButtonTapped() //Code also doesn't reach here
}
#IBAction func infoButtonTouched(_ sender: UIButton) {
delegate?.informationButtonTapped()
}
}
Keep in mind the code compiles fine, so I did have the infoButtonTouched function implemented, I just didn't see the point in showing it. I have no idea why the button is unresponsive. Any ideas on how to get the button to respond would be most helpful. Thanks for your consideration of this matter.
Sincerely,
Sean
I'm trying to render a custom view. The problem is that even after the view is loaded, its subviews are still equals to nil.. So not showing and impossible to configure. The custom view is setup through interface builder and all the outlets are linked to the properties you can see below.
Here is the custom UIView code :
import UIKit
class BadgeView : UIView
{
#IBOutlet weak var progressCircleView: CircleProgressView!
#IBOutlet weak var progressionValue: UILabel!
#IBOutlet weak var name: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Tell me if you need more informations.
How do you initialise BadgeView. If you are using storyboard or xib, the view should be initialised like this:
let nib = NSBundle.mainBundle().loadNibNamed("BadgeView", owner: self, options: nil)
let badgeView = nib[0] as! BadgeView