Custom UIButton - IBAction not working - ios

I have a default UIButton linked to an IBAction (touch up inside). This works fine, so I know my connection is OK. Once I change the UIButton class to my custom button, the IBAction is no longer triggered. Below is the code for my custom UIButton. Any ideas why this is happening?
import UIKit
#IBDesignable
class PrimaryButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
initView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initView()
}
private func initView() {
let view = viewFromNibForClass()
view.frame = bounds
view.autoresizingMask = [
UIViewAutoresizing.flexibleWidth,
UIViewAutoresizing.flexibleHeight
]
addSubview(view)
}
private func viewFromNibForClass() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil).first as! UIView
return view
}
}

Your code does not work because a button does not receive touches anymore. All touches are sent to the topmost custom view you add.
Set view.userInteractionEnabled = false to make it transparent to touches.

Your custom button is covered by the view you added.

Related

Button click not working for custom UIView

Code for the Custom UIView:
Please check the video too here: https://drive.google.com/open?id=1kbrOxXWcJIi4vkiqMNer3exBr5cOWgDz
import UIKit
protocol PostAttachmentFullScreenViewDelegate: class {
func closeAttachmentFullView()
}
class PostAttachmentFullScreenView: UIView {
weak var delegate: PostAttachmentFullScreenViewDelegate?
#IBOutlet var backgroundView: UIImageView!
#IBOutlet var closeButton: UIButton!
#IBAction func closeViewAction(_ sender: Any) {
print("will call delegate to put it off")
self.delegate?.closeAttachmentFullView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let _ = commonInitialization()
backgroundView.image = UIImage(named: "ScrollImageTop1")
closeButton.isUserInteractionEnabled = true
}
override init(frame: CGRect) {
super.init(frame: frame)
let _ = commonInitialization()
backgroundView.image = UIImage(named: "ScrollImageTop1")
closeButton.isUserInteractionEnabled = true
}
func commonInitialization() -> UIView
{
let bundle = Bundle.init(for: type(of: self))
let nib = UINib(nibName: "PostAttachmentFullScreenView", 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
}
}
usage in ViewController (I am defining an instance of the custom view and putting it inside the Scroll View):
var frame = CGRect(x:0, y:0, width:0, height:0)
let blue = PostAttachmentFullScreenView()
blue.delegate = self
blue.isUserInteractionEnabled = true
blue.backgroundColor = UIColor.blue
blue.backgroundView.image = fileAttachments[1]
frame.origin.x = attachmentsScrollView.frame.size.width * CGFloat (0)
frame.size = attachmentsScrollView.frame.size
blue.frame = frame
attachmentsScrollView.addSubview(blue)
extension NewPostViewController : PostAttachmentFullScreenViewDelegate
{
func closeAttachmentFullView() {
print("hiding attachments view")
attachmentSuperView.isHidden = true
}
}
To my surprise it doesn't even print - "will call delegate to put it off".
I am not able to understand what's wrong here. Please help me understand the issue and correct it. Thank you.
You are mixing programmatic approach and xib approach.
As you have added IBOultet and IBAction that means you are using xib for the UIView.
In that scenario you have to load the UIView xib when initialising the view.
Add an extension for UIView in your project:
extension UIView {
class func fromNib<T: UIView>() -> T {
return Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, options: nil)![0] as! T
}
}
when you are initialising your view add it like this :
let blue : PostAttachmentFullScreenView = UIView.fromNib()
blue.delegate = self
blue.isUserInteractionEnabled = true
blue.backgroundColor = UIColor.blue
blue.backgroundView.image = fileAttachments[1]
frame.origin.x = attachmentsScrollView.frame.size.width * CGFloat (0)
frame.size = attachmentsScrollView.frame.size
blue.frame = frame
attachmentsScrollView.addSubview(blue)
and the delegate and button action methods will work.
you missed this :
You never set the target/action on your button. Somewhere you need to call addTarget(_:action:for:) to set the target/action on the button. Also, what connects the button to your PostAttachmentFullScreenView as an outlet?
This might be an obvious one but for me (Xcode 10.1) adding all missing UI constraints to the UIButton in question (at least 4 constraints) fixed the error for me in my custom view:
Make sure you add enough constraints (typically 4 constraints) or enough to have all warnings regarding missing constraints removed. After doing this and attaching the button with Ctrl + drag from View to corresponding swift code, the click was being detected and working properly.
Hope this helps.

Customized Tab bar Using xib

I make Customized Tab bar Using xib I need to know how to Fetch tab bar bottom in to storyboard and I need to know how to autoresize this nib view for all views
Screenshot:
Define a UIView class named MyTabBar and use same class in place of UIView where you want to add your tab bar
class MyTabBar: NibView {
}
Now, create a superclass called NibView, which will handle everything about the XIB file merging
class NibView: UIView {
var view: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
}
extension NibView {
func xibSetup() {
view = loadNib()
view.translatesAutoresizingMaskIntoConstraints = false
view.frame = bounds
addSubview(view)
// add Constraints
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[childView]|", options: [], metrics: nil, views: ["childView": view]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[childView]|", options: [], metrics: nil, views: ["childView": view]))
}
}
extension UIView {
func loadNib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nibName = type(of: self).description().components(separatedBy: ".").last!
let nib = UINib(nibName: nibName, bundle: bundle)
return nib.instantiate(withOwner: self, options: nil).first as! UIView
}
}
More details can be found here on how to use a nib
https://medium.com/swift2go/swift-custom-uiview-with-xib-file-211bb8bbd6eb

Could not load NIB in bundle Xcode8

I've followed a tutorial but when I try to run my code it crashed because it couldn't load NIB in bundle.
Here's my code:
class BuyPremiumView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
// MARK: - Private Helper Methods
// Performs the initial setup.
fileprivate func setupView() {
let view = viewFromNibForClass()
view.frame = bounds
view.autoresizingMask = [
UIViewAutoresizing.flexibleWidth,
UIViewAutoresizing.flexibleHeight
]
addSubview(view)
}
// Loads a XIB file into a view and returns this view.
fileprivate func viewFromNibForClass() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
}
Does anybody know how to fix this?
if you would load view from nib i think best easy way is :
var yourView : YourView = NSBundle.mainBundle().loadNibNamed("myXib", owner: self, options: nil)[0] as! YourView
i hope this help

Frame size of UIView when loaded from Nib?

I am loading a UIView from a .xib file like this:
static func loadFromNib() -> CardView {
let nib = UINib(nibName: "CardView", bundle: nil)
return nib.instantiate(withOwner: self, options: nil).first as! CardView
}
When loaded the view has the exact frame size as set in "Frame Rectangle" of the Size Inspector in the Interface Builder.
Is this guaranteed? I need this size to be exact, because subview constraints are specific and will not fit if the view has the wrong size [*], but I didn't find any mention of this in Apple's docs.
[*] = Reason: I am rendering the view to an UIImage so I can display it in and UIImageView later on. It shows the image of a membership card and name and membership number need to be in the right place with the correct font size on all devices..
Set any UIView subclass as owner of xib, then load xib as subview of this view and set autoresizing mask.
This is how I use it:
extension UIView {
func loadXibView(with xibFrame: CGRect) -> UIView {
let className = String(describing: type(of: self))
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: className, bundle: bundle)
guard let xibView = nib.instantiate(withOwner: self, options: nil)[0] as? UIView else {
return UIView()
}
xibView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
xibView.frame = xibFrame
return xibView
}
}
xibView.autoresizingMask = [.flexibleWidth, .flexibleHeight] sets size of view properly.
Then just use it any UIView subclass in initialization:
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(loadXibView(with: bounds))
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
addSubview(loadXibView(with: bounds))
}
Create a custom class for your UIView:
class CardView: UIView {
override init(frame: CGrect) {
super.init(frame: frame)
let xibView = UINib(nibName: "CardView", bundle: nil).instantiate(withOwner: nil, options:nil)[0] as! UIView
self.addSubview(xibView)
}
require init?(coder: aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
and then call if from the class you'll be implementing it in with the frame size you need or otherwise it will default to the size that is set in your interface builder:
// MyViewController
var cardView: CardView?
override func viewDidLoad() {
super.viewDidLoad()
self.cardView = CardView()
self.cardView.frame.size = CGSize(size here)
self.cardView.frame.origin = CGPoint(point here)
self.view.addSubview(self.cardView!)
}

Addsubview custom xib file error

I'm using Swift 3, I have error adding xib file as subview
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "CustomView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.addSubview(view);
Can someone help me please?
In my Custom View Class i implemented as follow:
import UIKit
#IBDesignable class TestView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
loadViewFromNib()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func loadViewFromNib(){
let view = Bundle.main.loadNibNamed("test", owner: self, options: nil)?.first as! UIView
print(view.backgroundColor ?? UIColor.blue)
}
}
then In my ViewController where i want add this custom view i write as below:
let view = TestView()
and i dont find any crash.
Try this, it is for swift 3.
let view = Bundle.main.loadNibNamed("CustomView", owner: self, options: nil)?.first as! UIView
self .addSubview(view)

Resources