Cannot call method of a button from a custom UIView - ios

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.

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")
}
}

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)

IOS Swift3 how to Remove Custom UIView randomly

I am building an iOS Application in swift 3, where I am creating dynamic UIViews. I need to remove custom view randomly. Please help me I am stuck with this for a long time. Thanks In Advance
class ViewController: UIViewController {
var myView: subView!
var y : CGFloat!
#IBOutlet weak var addButton: UIButton!
override func viewDidLoad() {
y = 1
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func cancelbutton(_ sender: UIButton) {
myView.removeFromSuperview()
}
#IBAction func buttonAction(_ sender: Any) {
y = y + 110
myView = subView(frame: CGRect(x: 80, y: y, width: 300, height: 100))
myView.backgroundColor = UIColor.green
myView.actionButton.addTarget(self, action: (#selector(cancelbutton(_:))), for: UIControlEvents.touchUpInside)
self.view.addSubview(myView)
}
}
As you can see in the above image when i click on Close the SubView(custome View) closes, but where as MyView with green color does not go and stays there. Someone please Help.........
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
Bundle.main.loadNibNamed("subView",owner: self, options:nil)
self.addSubview(self.views)
Bundle.main.loadNibNamed("subView",owner: self, options:nil)
self.addSubview(self.views)
}
override init(frame: CGRect)
{
super.init(frame: frame)
Bundle.main.loadNibNamed("subView", owner: self, options: nil)
views.frame = bounds
self.addSubview(self.views)
}
#IBAction func buttonAction(_ sender: Any) {
views.removeFromSuperview()
}
The thing you are doing wrong is that you add multiple views of subView that why you selected does not remove. Please modify your code like given below.
The thing I have done is that whenever you will add new subView you will also set its tag value and when you select view to remove its tag value and place an if statement on that tag value.
class ViewController: UIViewController {
var myView: subView!
var y : CGFloat!
var tag : Int = 0
#IBOutlet weak var addButton: UIButton!
override func viewDidLoad() {
y = 1
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func cancelbutton(_ sender: UIButton)
{
let selectViewTagValue : Int = sender.tag /// save the selected view tag value
for object in self.view.subviews {
if ((object is subView) && object.tag == selectViewTagValue)
{
object.removeFromSuperview()
}
}
}
#IBAction func buttonAction(_ sender: Any) {
y = y + 110
myView = subView(frame: CGRect(x: 80, y: y, width: 300, height: 100))
myView.tag = tag
myView.actionButton.tag = tag
tag = tag + 1
myView.backgroundColor = UIColor.green
myView.actionButton.addTarget(self, action: (#selector(cancelbutton(_:))), for: UIControlEvents.touchUpInside)
self.view.addSubview(myView)
}
Try to change cancel action like this:
func cancelbutton(_ sender: UIButton)
{
if let myView = sender.superview {
myView.removeFromSuperview()
}
}
Just remove the button's container view, not the global myView.
I managed to fixed the delete issue, but currently I am unable to relocate the positions the customs views, as shows in the picture below, Kindly help me with this.

Overlay an UIButton over an UIWebView in Swift

So I have a view that loads a UIWebView and I want to overlay UIButton the user can tap on to go to another view.
I managed to place the button over the web view but I can't seem to be able to tap on it.
Here's my code:
class ButtonView: UIView {
var button: UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
button = UIButton(frame: CGRectMake(0, 0, 50, 50))
button.layer.zPosition = 10
self.addSubview(button)
}
required init(coder aDecoder: NSCoder) {
fatalError("Init(coder:) has not been implemented")
}
}
class MyViewController : UIViewController, UIWebViewDelegate {
var buttonView = ButtonView()
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
self.loadWebView() //This just loads a url to the web view...
webView.layer.zPosition = 1
buttonView = ButtonView(frame: CGRectMake(0, 0, 100, 100))
buttonView.layer.zPosition = 100
buttonView.button.addTarget(self, action: "buttonEvent:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(buttonView)
}
func buttonEvent(sender: AnyObject!){
println("Tap detected!")
}
}
So this displays the button on top of the web view as expected but I can't tap on it.
Although if I hide the web view I can tap on the button without any problems
Is this a zPosition problem? or something else?
It could work as it is as long as you replace:
self.view.addSubview(buttonView)
With:
webView.addSubview(buttonView)
So basically add the view containing the button to the web view instead

UIButton in Swift - action is not working

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)
...
}

Resources