UIButton in Swift - action is not working - ios

I'm writing my first IOs app. I have my class animation where I register an action for my button
class animation {
var view: UIView!
init(var viewLink:UIView) {
self.view = viewLink
let buttonNext = UIButton.buttonWithType(UIButtonType.System) as UIButton
buttonNext.frame = CGRectMake(200, 250, 100, 50)
buttonNext.addTarget(self, action: "nextActionButton:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(buttonNext)
}
}
class ViewController: UIViewController {
private var animClass: animation?
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
animClass = animation(viewLink: self.view)
}
func nextActionButton(sender:UIButton!) {
println('rrr')
}
}
I have an error:
NSForwarding: warning: object 0x7fd820c94c00 of class 'animation.animation' does not implement methodSignatureForSelector: -- trouble ahead
Unrecognized selector -[animation.animation nextActionButton:]
Can you help me please what am I doing wrong?

You're setting the button's action to target the animation object where the actual method is defined in your ViewController.
You should pass the ViewController in to the animation's init class and use it as the target:
init(var viewLink:UIView, eventTarget : AnyObject) {
...
buttonNext.addTarget(eventTarget, action: "nextActionButton:", forControlEvents: UIControlEvents.TouchUpInside)
...
}
...
override func viewDidLoad() {
...
animClass = animation(viewLink: self.view, eventTarget:self)
...
}

Related

Add action to button from ViewController

I have a problem adding a target from a view controller to the button that is created in a view (no action when it is pressed). But if I create the button in the view controller directly then it works.
What could be wrong here?
class ViewController: UIViewController {
var mainView = MainView()
var counter:Int = 0
#objc func buttonAction(sender:UIButton!)
{
counter += 1
print("Button was predded:\(counter)")
mainView.lable1.text = "Button was predded:\(counter)"
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(mainView)
mainView.buttno1.addTarget(self, action: #selector(buttonAction), for: UIControl.Event.touchUpInside)
}
}
class MainView : UIView {
var background: UIView = {
return background
}()
lazy var buttno1: UIButton = {
var btn = UIButton()
....
return btn
}()
func createButton1(){
print("Main view btn created")
background.addSubview(buttno1)
}
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(background)
createButton1()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Cannot call method of a button from a custom UIView

I want to call an action from a button which is inside a custom View. The view itself is part of a UIViewController. But when I tapped the view, nothing happens. I do not know where my mistake is, although my code looks like the ones on stackoverflow.
protocol StoreDelegate: class {
func didPressButton(_ sender: UIButton)
}
class Store: UIView {
weak var delegate:StoreDelegate?
var button: UIButton = {
let button = UIButton()
button.setTitle("button", for: .normal)
button.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
button.backgroundColor = .red
button.addTarget(self, action: #selector(buttonPress(_:)), for: .touchUpInside)
return button
}()
override init(frame: CGRect) {
super.init(frame:frame)
self.addSubview(button)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
#objc func buttonPress(_ sender: UIButton) {
delegate?.didPressButton(sender)
print("here")
}
}
And this is my ViewController:
class ViewController: UIViewController, StoreDelegate{
var testView = Store()
override func viewDidLoad() {
super.viewDidLoad()
testView.delegate = self
self.view.addSubview(testView)
}
func didPressButton(_ sender: UIButton) {
print("Hello")
}
}
Neither it prints "Hello" nor "Here". Maybe I have misunderstood the protocol/delegate pattern.
You need to set constraints or a frame to the view
testView.frame = ///////
It's the base behind receiving actions
You can implement override sizeToFit in Store class to match your needs:
override func sizeToFit() {
frame.size = button.frame.size
}
Then you can call it like:
testView.sizeToFit()
You may consider using autolayout for better sizing.

Change the background of a view controller using a subclassed UIButton in a separate file

I'm a beginner to Swift/iOS programming. I'm trying to do things programmatically. I created a subclass of a UIButton in a separate swift file. My objective is to just change the background of the underlying ViewController.
CustomButton.swift
import UIKit
class CustomButton: UIButton{
override init(frame: CGRect) {
super.init(frame: frame)
self.translatesAutoresizingMaskIntoConstraints = false
self.backgroundColor = .blue
self.setTitleColor(.white, for: .normal)
self.setTitle("Press Me", for: .normal)
self.layer.cornerRadius = 15
// Button Action
self.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
}
#objc func buttonPressed() {
// Verify the method is called when the button is pressed
self.setTitle("Pressed", for: .normal)
// Change the background color for the ViewController
let vc = ViewController()
vc.view.backgroundColor = .red
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
ViewController.swift
import UIKit
class ViewController: UIViewController{
let myButton = CustomButton()
fileprivate func addElements() {
view.addSubview(myButton)
myButton.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 60).isActive = true
myButton.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -60).isActive = true
myButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 400).isActive = true
myButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -400).isActive = true
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
addElements()
}
}
I'm not sure why this doesn't work or what I'm missing.
This doesn't work because you are creating a brand new VC here:
// Change the background color for the ViewController
let vc = ViewController() // This VC is not the same one as the one that's presented on screen
vc.view.backgroundColor = .red
Your custom UIButton do not and should not know about the view controller that controls it. The VC should handle this.
Your UIButton subclass should just be:
class CustomButton: UIButton{
override init(frame: CGRect) {
super.init(frame: frame)
self.translatesAutoresizingMaskIntoConstraints = false
self.backgroundColor = .blue
self.setTitleColor(.white, for: .normal)
self.setTitle("Press Me", for: .normal)
self.layer.cornerRadius = 15
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
You should add your VC as a target for the button, in the VC.
What I mean is:
// in viewDidLoad
let button = CustomButton(...)
button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
// ...
func didTapButton() {
view.backgroundColor = .red
}
If you want to change the background color of UIViewController then you have to pass that controller.
Follow these steps:-
1st step - Create a custom button class and create a viewController variable type of UIViewController so you can assign the specific controller to change the background of UIViewController color.
import UIKit
class CustomButton: UIButton {
var viewController: UIViewController?
override func awakeFromNib() {
super.awakeFromNib()
self.addTarget(self, action: #selector(buttonPressed(sender:)), for: .touchUpInside)
}
#objc func buttonPressed(sender: UIButton) {
viewController?.view.backgroundColor = UIColor.red
}
}
2nd step - UIViewController code
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var button: CustomButton!
override func viewDidLoad() {
super.viewDidLoad()
button.viewController = self //Assigning controller using self keyword
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
}
}
This is happening because your ViewController instance is changed. You are trying to change ViewController's backgroundcolor by creating new instance of it in your buttonPressed() method. So that the current instance of your ViewController and this newly created instance are different so background color is not changed.
You can do it by adding Notification to your ViewController class and post this Notification in your button action that is buttonPressed().
Follow these steps as below:
Add this code in your ViewController's viewDidLoad() :
NotificationCenter.default.addObserver(self, selector: #selector(changeBackgroundColor), name: NSNotification.Name(rawValue: “load”), object: nil)
Add below function in your ViewController.swift file:
as -
func changeBackgroundColor() {
self.view.backgroundColor = UIColor.purple
}
Now post this above Notification in buttonPressed() as - NotificationCenter.default.post(name: Notification.Name(rawValue: "load"), object:nil)

Swift:class does not implement methodSignatureForSelector: -- trouble ahead Unrecognized selector

class FirstView: UIView {
#IBOutlet weak var lbl1: UILabel!
#IBOutlet weak var lbl1: UILabe2!
#IBOutlet weak var btn1: UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
func setupView() {
//view setups
}
}
Now in next class i am trying to get the action event of the button but it always charshes saying class 'App. UIViewHelper' does not implement methodSignatureForSelector: -- trouble ahead
Unrecognized selector +[App. UIViewHelper NotesClicked:]
class UIViewHelper
{
case 1:
let lowerDetail = FirstView()
lowerDetail.lbl1.text = "Worked"
lowerDetail.lblw.text = "Happy"
lowerDetail.btn1.addTarget(self, action: #selector(NotesClicked), forControlEvents: UIControlEvents.TouchUpInside)
print("Sleep")
break
}
#objc func NotesClicked(sender :UIButton) {
print("Worked")
}
}
and when UIViewHelper extends NSObject is crashes saying * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[App.UIViewHelper NotesClicked:]: unrecognized selector sent to class 0x105771a80'
I am confused what is happening here.Can anybody suggest this??
I think that your problem is that you do not subclass NSObject from UIViewHelper, try:
class UIViewHelper : NSObject{
You trying to add a selector from a static function to an instance of UIViewHelper.
When you are saying
lowerDetail.btn1.addTarget(self, action: #selector(NotesClicked), forControlEvents: UIControlEvents.TouchUpInside)
You are adding a target action to self (an instance of UIViewHelper), but, from a static function.
I suppose you do not create an instance of UIViewHelper, like you mentioned in the comment that the switch case is called from a static function, and therefore the target is referencing a nil object.
To fix the code, you need to keep a reference to UIViewHelper, and not call it from a static function.
How to do it? Here is a short snippet to give you an idea in Swift 4.
class ViewController: UIViewController {
let uiHelper = UIViewHelper()
override func viewDidLoad() {
super.viewDidLoad()
let some = uiHelper.makeView()
self.view.addSubview(some)
}
}
class UIViewHelper {
func makeView() -> FirstView {
let lowerDetail = FirstView(frame: CGRect(origin: .zero, size: CGSize(width: 39, height: 39)))
lowerDetail.lbl1.text = "Worked"
lowerDetail.lbl2.text = "Happy"
lowerDetail.btn1.addTarget(self, action: #selector(UIViewHelper.NotesClicked), for: .touchUpInside)
return lowerDetail
}
#objc func NotesClicked(sender :UIButton) {
print("Worked")
}
}

Custom UIView in NavigationController titleView. How can I have the buttons trigger actions in my View Controller

I have a custom uiview (call it navBarMenu) with five buttons as subviews. I added this navBarMenu to the navigationbar's titleView. The navBarMenu has its own class and nib file where the buttons are defined as iboutlets. How can I add targets so that when I click the button in the navBarMenu it will trigger a function in my viewcontroller that is embedded in the navigation controller?
Using the method: navBarMenu.Button1.addTarget(self, action: "Button1Tapped:", forControlEvents: UIControlEvents.TouchUpInside) does not work and I get an error that it unexpectedly found nil while unwrapping an Optional value.
Edit: Here is the code for my view controller and my custom view.
class MyCustomView: UIView {
var view: UIView!
var nibName: String = "MyCustomView"
#IBOutlet weak var Button1: UIButton!
#IBOutlet weak var Button2: UIButton!
#IBOutlet weak var Button3: UIButton!
#IBOutlet weak var Button4: UIButton!
#IBOutlet weak var Button5: UIButton!
var Button1Text: String? {
get {
return Button1.titleLabel?.text
}
set(Button1Text) {
Button1.setTitle(Button1Text, forState: UIControlState.Normal)
}
}
var Button2Text: String? {
get {
return Button2.titleLabel?.text
}
set(Button2Text) {
Button2.setTitle(Button2Text, forState: UIControlState.Normal)
}
}
var Button3Text: String? {
get {
return Button3.titleLabel?.text
}
set(Button3Text) {
Button3.setTitle(Button3Text, forState: UIControlState.Normal)
}
}
var Button4Text: String? {
get {
return Button4.titleLabel?.text
}
set(Button4Text) {
Button4.setTitle(ButtonText4, forState: UIControlState.Normal)
}
}
var Button5Text: String? {
get {
return Button5.titleLabel?.text
}
set(Button5Text) {
Button5.setTitle(ButtonText5, forState: UIControlState.Normal)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
println("view is setup")
}
convenience init(controller: UIViewController) {
var frameForNavBar: CGRect = CGRect(x: 0.0, y: 0.0, width: 548.0, height: 33.0)
self.init(frame: frameForNavBar)
Button1.addTarget(controller, action: "Button1Tapped:", forControlEvents: UIControlEvents.TouchUpInside)
Button2.addTarget(controller, action: "Button2Tapped:", forControlEvents: UIControlEvents.TouchUpInside)
Button3.addTarget(controller, action: "Button3Tapped:", forControlEvents: UIControlEvents.TouchUpInside)
Button4.addTarget(controller, action: "Button4Tapped:", forControlEvents: UIControlEvents.TouchUpInside)
Button5.addTarget(controller, action: "Button5Tapped:", forControlEvents: UIControlEvents.TouchUpInside)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setup() {
view = loadViewFromNib()
view.frame = bounds
addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: nibName, bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}
class MyViewController: UIViewController, UINavigationBarDelegate {
#IBOutlet weak var webView: UIWebView!
func Button1Tapped(sender: AnyObject) {
println(__FUNCTION__)
}
func Button2Tapped(sender: AnyObject) {
println(__FUNCTION__)
}
func Button3Tapped(sender: AnyObject) {
println(__FUNCTION__)
}
func Button4Tapped(sender: AnyObject) {
println(__FUNCTION__)
}
func Button5Tapped(sender: AnyObject) {
println(__FUNCTION__)
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: "MyViewController", bundle: nil)
}
convenience init() {
self.init(nibName: "MyViewController", bundle: nil)
tabBarItem.title = "MyVC"
tabBarItem.image = UIImage(named: "MyImage")
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
let navBarMenu = MyCustomView(controller: self)
positionForBar(navigationController!.navigationBar)
self.navigationItem.titleView = navBarMenu
self.navigationController?.navigationBar.translucent = false
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadWebPage() {
}
func positionForBar(bar: UIBarPositioning) -> UIBarPosition {
return UIBarPosition.TopAttached
}
}
When you initialize your customView you can pass the UIViewController parameter and then add target for your button to it.
let myCustomView = MyCustomViewClass(self)
And in your MyCustomViewClass you can use:
init (controller: UIViewController) {
// use controller, not self
button.addTarget(controller, action: "Button1Tapped:", forControlEvents: UIControlEvents.TouchUpInside)
}

Resources