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
Related
I am using this code:
import UIKit
class SnackBarView: UIView {
#IBOutlet var containerView: UIView!
#IBOutlet var labelText: UILabel!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let _ = commonInitialization()
}
func commonInitialization() -> UIView
{
let bundle = Bundle.init(for: type(of: self))
let nib = UINib(nibName: "SnackBarView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
addSubview(view)
return view
}
}
when I try initialising it like this:
let snackBar = SnackBarView()
it gives the error:
Missing argument for parameter 'coder' in call
I know there is something wrong in the init function but I am not sure how to correct this. How should I proceed correcting this?
The error is not in your class but rather in how you are attempting to call it.
Since you want to create the UIView with zero (0) parameters you need to supply it a constructor (init) to deal with that situation when it happens.
Hopefully the below will work to give you a constructor with zero (0) parameters.
class SnackBarView: UIView {
#IBOutlet var containerView: UIView!
#IBOutlet var labelText: UILabel!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let _ = commonInitialization()
}
// you need to add this init
override init(frame: CGRect) {
super.init(frame: frame)
// call your custom initialization code here
let _ = commonInitialization()
}
// constructor with zero (0) parameters
convenience init() {
// call the override from above with a default CGRect
self.init(frame: CGRect.zero)
}
func commonInitialization() -> UIView
{
let bundle = Bundle.init(for: type(of: self))
let nib = UINib(nibName: "SnackBarView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
addSubview(view)
return view
}
}
You need to add override init(frame: CGRect) in your view: updated code is below:
class SnackBarView: UIView {
#IBOutlet var containerView: UIView!
#IBOutlet var labelText: UILabel!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let _ = commonInitialization()
}
// you need to add this init
override init(frame: CGRect) {
super.init(frame: frame)
}
func commonInitialization() -> UIView
{
let bundle = Bundle.init(for: type(of: self))
let nib = UINib(nibName: "SnackBarView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
view.frame = bounds
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
addSubview(view)
return view
}
}
I think it's meaningless to create a UIView with xib , and then add an instance of the same type to it as commonInitialization here occupies all frame of itself , I think you need
class SnackBarView: UIView {
#IBOutlet var containerView: UIView!
#IBOutlet var labelText: UILabel!
class func commonInitialization(_ rec:CGRect) -> SnackBarView
{
let nib = UINib(nibName: "SnackBarView", bundle: nil)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! SnackBarView
view.frame = rec
return view
}
}
//
let v = SnackBarView.commonInitialization(view.frame)
view.addSubview(v)
I had created some custom UIViews and implemented in another UIView in my projects.
I'm getting a crash while calling some functions or setting values to some objects but not getting crash when setting property.
Refer below code to understand code and question properly.
class SearchProfileDetailView: UIView {
#IBOutlet weak var userInfoTable: UITableView!
var userObject: UserObject?
override init(frame:CGRect) {
super.init(frame: frame)
loadViewFromNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadViewFromNib()
}
func loadViewFromNib() {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "SearchProfileDetailView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
view.frame = bounds
self.addSubview(view);
}
func setColor() {
self.backgroundColor = UIColor.red
}
}
I've used this SearchProfileDetailView in another UIView with the interface builder and assigned outlet refer below code.
class SearchResultView: UIView {
#IBOutlet weak var profileDetailView: SearchProfileDetailView!
var currentIndex: Int?
override init(frame:CGRect) {
super.init(frame: frame)
loadViewFromNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadViewFromNib()
}
func loadViewFromNib() {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "SearchResultView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
view.frame = bounds
self.addSubview(view);
}
func setUserProfile(userObject: UserObject) {
profileDetailView.backgroundColor = UIColor.red // Not Crashed
profileDetailView.userObject = userObject //Crashed with error mentioned in title of question
profileDetailView.setColor() ////Crashed with error mentioned in title of question
}
}
Crashed while calling profileDetailView.setColor() and
profileDetailView.userObject = userObject But not crashed on
profileDetailView.backgroundColor = UIColor.red
Now I've used this SearchResultView into UIViewController with the interface builder.
class ExploreViewController: UIViewController {
#IBOutlet weak var searchResultView: SearchResultView!
func getResult() {
SearchAPIHandler().search(params: parameters) {[weak self] (responseData) in
DispatchQueue.main.async {
guard let strongSelf = self else {
return
}
if let users = responseData.users, !users.isEmpty {
strongSelf.searchResultView.setUserProfile(userObject: users[0])
}
}
}
}
I had tried so much and now I've got to know that problem was with my interface builder.
There was none module.
I checked Inherit Module From Target and everything works well.
I have created a custom view from xib(freeform) in which there are two button (Login and cancel) and i have present it at a view according to some condition. Custom view get present on another view nicely but the button(Login an cancel) not getting any touch event.
Code of custom class and init method:
import UIKit
class customAlertView: UIView {
#IBOutlet weak var messageLabel: UILabel!
#IBOutlet weak var loginButton : UIButton!
#IBOutlet weak var cancelButton: UIButton!
var view : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
view = setUpFromXib()
view.frame = frame
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "customAlertView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
translatesAutoresizingMaskIntoConstraints = true
return view
}
#IBAction func loginButtonAction(sender: AnyObject) {
}
#IBAction func cancelButtonAction(sender: AnyObject) {
}
}
This is the block of code from where i have add the custom view as a subview.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if Reachability.isConnectedToNetwork() {
categoryObj = categoryArray .objectAtIndex(indexPath.row) as! TECategoryDetails
if categoryObj.categoryType == "premium" {
let screen = UIScreen.mainScreen().bounds
customView = customAlertView.init(frame: CGRect(origin: CGPoint(x: 0,y: 80), size: CGSize(width: screen.width, height: screen.height/3)))
self.view .addSubview(customView)
}
else{
watchAllFlag = false
self.performSegueWithIdentifier("Episode", sender: self)
}
}
else {
self.showAlertPopUp()
}
}
You can also do like this way.
import UIKit
class customAlertView: UIView {
#IBOutlet weak var messageLabel: UILabel!
#IBOutlet weak var loginButton : UIButton!
#IBOutlet weak var cancelButton: UIButton!
var view : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
view = setUpFromXib()
view.frame = frame
loginButton.addTarget(self, action: Selector(“loginButtonAction:”), forControlEvents: .TouchUpInside)
cancelButton.addTarget(self, action: Selector(“cancelButtonAction:”), forControlEvents: .TouchUpInside)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "customAlertView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
translatesAutoresizingMaskIntoConstraints = true
return view
}
func loginButtonAction(sender: AnyObject) {
}
func cancelButtonAction(sender: AnyObject) {
}
}
Check it, its working:
ViewController.swift:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func displayAlertBtnTapped(sender: AnyObject) {
let screen = UIScreen.mainScreen().bounds
let customView = CustomAlertView.init(frame: CGRect(origin: CGPoint(x: 0,y: 80), size: CGSize(width: screen.width, height: screen.height/3)))
self.view .addSubview(customView)
}
}
CustomAlertView.swift:
import UIKit
class CustomAlertView: UIView {
#IBOutlet weak var loginButton : UIButton!
#IBOutlet weak var cancelButton: UIButton!
var view : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
view = setUpFromXib()
view.frame = frame
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "CustomAlertView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
translatesAutoresizingMaskIntoConstraints = true
return view
}
#IBAction func loginButtonAction(sender: AnyObject) {
print("Login button clicked");
}
#IBAction func cancelButtonAction(sender: AnyObject) {
print("Cancel button clicked");
}
}
For testing, use the following GitHub link:
https://github.com/k-sathireddy/AlertViewSample
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()
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?