addTarget() does not work on custom extensions - swift

I made a custom UIView() and i'm trying to add a okButton to it.
However. I have added the button but when showing my UIView in one of my ViewControllers, But the button won't work. This is my code:
class Luna: UIView {
let luna = UIView()
let okButton = UIButton()
typealias completionHandler = (_ success:Bool) -> Void
// Not yet implemented
open var touchOutsideToHide: Bool = true;
private var screenWidth: CGFloat {
return UIScreen.main.bounds.width
}
override init(frame: CGRect) {
super.init(frame: frame)
okButton.setTitleColor(.blue, for: .normal)
okButton.setTitle("Okay", for: .normal)
okButton.titleLabel?.font = UIFont(name: "avenirnext-demibold", size: 16)
let gesture:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.pressButton(_:)))
okButton.addGestureRecognizer(gesture)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
//The target function
#objc func pressButton(_ sender: UIButton){ //<- needs `#objc`
// .. //
print("btn hit")
}
I do not get btn hit in the console and the tap isn't registered
the button is visible, it's added as a subview:
Screenshot

Button have default touch gesture, you don't need to add it. just add target as follow to fix your issue. Create protocol of your customer class and declare delegate for it in same class as follow.
protocol LunaDelegate: class {
func okButtonTapped(sender: UIButton)
}
class Luna: UIView {
let luna = UIView()
let okButton = UIButton()
typealias completionHandler = (_ success:Bool) -> Void
weak var delegate: LunaDelegate?
// Not yet implemented
open var touchOutsideToHide: Bool = true;
private var screenWidth: CGFloat {
return UIScreen.main.bounds.width
}
override init(frame: CGRect) {
super.init(frame: frame)
okButton.setTitleColor(.blue, for: .normal)
okButton.setTitle("Okay", for: .normal)
okButton.titleLabel?.font = UIFont(name: "avenirnext-demibold", size: 16)
okButton.addTarget(self, action: #selector(pressButton(sender:)), for: .touchUpInside)
}
#IBAction func pressButton(sender: UIButton) {
if let selfDelegate = self.delegate {
selfDelegate.okButtonTapped(sender: sender)
}
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Then after implement your code as follow to use your custom view. When your button will pressed then delegate method will be call in your view controller.
Usage:
class LunaViewController: UIViewController, LunaDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let luna = Luna(frame: CGRect.init(x: 100, y: 100, width: 100, height: 40))
luna.delegate = self
self.view.addSubview(luna)
}
// MARK:- Luna Delegate
func okButtonTapped(sender: UIButton) {
print("OK Button Pressed From Luna View")
}
}
This is the proper solution which I have already using in my current project. I hope this will help you.

Related

On swift, how to hide cursor and disable cut/paste for UITextfield programmatically

I face a problem when a create a sub class of UITexfield to hide the copy/past etc... buttons when i click on the TextField. here is the code of the class:
class UITextFieldCustom: UITextField {
var enableLongPressActions = false
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!}
override init(frame: CGRect) {
super.init(frame: frame)}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return enableLongPressActions
}
}
The code runs good when i use it for a texfield from a storyboard, but when the textField is made programaticaly, i receveive the message: Thread 1: signal SIGABRT
here is the declaration of my textField on a part of my code in an extension of my View Controller :
extension MenuViewController {
func tabBarCentre(nameTextField: UITextFieldCustom) {
let titleLeftbutton = UIButton(type: .system)
titleLeftbutton.tintColor = #colorLiteral(red: 0.370555222, green: 0.3705646992, blue: 0.3705595732, alpha: 1)
let leftButtonConfig = UIImage.SymbolConfiguration(
pointSize: 20,
weight: .bold,
scale: .small)
let leftButtonImage = UIImage(
systemName: "chevron.left",
withConfiguration: leftButtonConfig)
titleLeftbutton.setImage(leftButtonImage, for: .normal)
titleLeftbutton.addTarget(self, action: #selector(dateMoinsUn), for: .touchUpInside)
// Création du text central qui recevra le DatePicker
nameTextField.frame = CGRect(x: 0, y: 0, width: 70, height: 25)
nameTextField.backgroundColor = #colorLiteral(red: 0.9685223699, green: 0.9686879516, blue: 0.9685119987, alpha: 1)
nameTextField.placeholder = "Ajouter date"
nameTextField.font = nameTextField.font?.withSize(15)
nameTextField.font = UIFont.preferredFont(forTextStyle: .headline)
nameTextField.textAlignment = .center
the error message is in my viewController :
class MenuViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tabBarCentre(nameTextField: titleNavBarTextField) // THE ERROR IS HERE !!!!
self.titleNavBarTextField.setInputViewDatePicker(target: self, textField: titleNavBarTextField, selector1: #selector(tapped), selector2: #selector(todayPressed))
titleNavBarTextField.text = displayToday()
}
}
thank you.
Add this methods to your code and see the changes. You can also customize what you can do with your textfield. If you want all textfield actions to be disabled then just "return false" in func canPerformAction method.
override func caretRect(for position: UITextPosition) -> CGRect {
return CGRect.zero
}
override func selectionRects(for range: UITextRange) -> [UITextSelectionRect] {
return []
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(UIResponderStandardEditActions.cut(_:)) || action == #selector(UIResponderStandardEditActions.selectAll(_:)) || action == #selector(UIResponderStandardEditActions.paste(_:)) {
return false
}
// Default
return super.canPerformAction(action, withSender: sender)**

Button on subview untouchable after add to view program

I try to add a subview to a view, but after added, the button on subview is untouchable. I have check the status of button, user interaction is enable. and after add subview, the UI of subview are show up correctly.
The subview class:
class ErrorInfoView: UIView {
#IBOutlet var containerView: UIView!
#IBOutlet weak var messageLabel: UILabel!
var callback: (()->())?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
func commonInit() {
Bundle.main.loadNibNamed("ErrorInfoView", owner: self, options: nil)
containerView.frame = self.bounds
containerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
containerView.backgroundColor = UIColor.clear
addSubview(containerView)
}
func configure(message: String, callback: #escaping ()->()) {
self.messageLabel.text = message
self.callback = callback
}
#IBAction func pressRetryButton(_ sender: UIButton) {
self.callback?()
}
}
The parent view:
let errorView = ErrorInfoView(frame: self.tableViewContainer.frame)
errorView.configure(message: error) {
// do something, but not be called
}
self.tableViewContainer.addSubview(errorView)
self.tableViewContainer.bringSubviewToFront(errorView)
errorView.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint = errorView.centerXAnchor.constraint(equalTo: self.tableViewContainer.centerXAnchor)
let verticalConstraint = errorView.centerYAnchor.constraint(equalTo: self.tableViewContainer.centerYAnchor)
self.tableViewContainer.addConstraints([horizontalConstraint, verticalConstraint])

xib convert to programmatically view

I need to use custom views instead of views created with xib file.
How do I convert and use nib/xib file to programmatically view ?
class CustomCell: UITableViewCell {
var item: ViewModelItem? {
didSet {
titleLabel?.text = item?.title
}
}
override func awakeFromNib() {
super.awakeFromNib()
selectionStyle = .none
}
#IBOutlet weak var titleLabel: UILabel?
static var nib:UINib {
return UINib(nibName: identifier, bundle: nil)
}
static var identifier: String {
return String(describing: self)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
accessoryType = selected ? .checkmark : .none
}
}
I added it instead of xib. How should i send this?
I want the xib file to be programmatically added and controllable.
I want the xib file to be programmatically added and controllable.
class CustomCellView: UIView {
convenience init(frame: CGRect,checkboxTag:Int?) {
self.init(frame: frame)
self.addCustomView(checkboxTag: checkboxTag)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addCustomView(checkboxTag : Int?) {
var checkbox: UIButton = ClickingCheckbox()
if((checkboxTag) != nil)
{
checkbox.tag = checkboxTag!
}
self.addSubview(checkbox)
}
}
class ClickingCheckbox: UIButton {
convenience init() {
self.init(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
self.setImage(UIImage(named: "unfilled.png"), for: UIControlState.selected)
self.setImage(UIImage(named: "filled.png"), for: UIControlState.normal)
self.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
}
#objc private func buttonTapped() {
self.isSelected = !self.isSelected
}
}
When you are using view from Nib, it calls AwakeFromNib() method, custom views from code are using Init() methods.
To convert you Xib to programmatically code you need to setup all UI inside Init() method and move all initialConfiguration methods from AwakeFromNib() to Init()

Custom view failed to render instance of the agent - crashes when setting a UIImage

I have a custom view with a button.
When adding the view in storyboard i get an error:
failed to render instance of the agent
When i debug the view from interface builder it crashes when it sets the image of the button.
CODE:
#IBDesignable
class UIHeader: UIView {
private lazy var backButton: UIButton = {
let btn = UIButton()
btn.tintColor = UIColor.lightGrayColor()
btn.translatesAutoresizingMaskIntoConstraints = false
//CRASH HERE//
btn.setImage(UIImage(named: "prev")!.imageWithRenderingMode(.AlwaysTemplate), forState: .Normal)
btn.addTarget(self, action: #selector(UIHeader.OnBackButtonClickLister(_:)), forControlEvents: .TouchUpInside)
return btn
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
}
extension UIHeader {
#IBInspectable
var backButtonImage: UIImage? {
get {
return backButton.imageForState(.Normal)
}
set (newImage) {
backButton.setImage(newImage?.imageWithRenderingMode(.AlwaysTemplate), forState: .Normal)
}
}
}
extension UIHeader {
private func setupView() {
translatesAutoresizingMaskIntoConstraints = false
addSubview(backButton)
}
}

How to add a class method in addtarget UIButton?

I have two classes and one of them I create a button which, I want to call a method in this class.
class blueFooterForImages: UIView{
//buttons for footer
let slideButton = UIButton()
let buttonOnFooter = UIButton()
override init(frame: CGRect) {
super.init(frame: frame)
//setting buttons
slideButton.frame = CGRectMake((self.frame.width / 2) - 10 , 10, 30, 30)
slideButton.addTarget(self, action: "animationFunction:", forControlEvents: UIControlEvents.TouchUpInside)
slideButton.setImage(imageForSlideButton,forState: .Normal)
self.addSubview(slideButton)}
}
internal func animationFunction(sender: UIButton!) {
UIView.animateWithDuration(0.5, animations: { () -> Void in
self.frame.size.width -= 100
})
}
add this to your code, use singleton and send the instance
static var sharedInstance : blueFooterForImages?
override init(frame: CGRect) {
super.init(frame: frame)
blueFooterForImages.sharedInstance = self
//rest of init code....
}
in other class:
var button = UIButton(initParams...);
button.addTarget(blueFooterForImages.sharedInstance!,action:"animationFunction:", forControlEvents: UIControlEvents.TouchUpInside);
just make sure that blueFooterForImages.sharedInstance is not nil
(make sure that blueFooterForImages instance was created before you do this)