How to declare a programmed button as a var - ios

I would to do a programmed button without the storyboard. The problem is that I can not call the button in a separate function like I can when I drag and drop a UIButton from a storyboard into a view controller. I do not want to use the storyboard at all.
//Trying to Create a var for btn
override func viewDidLoad() {
super.viewDidLoad()
let btn = UIButton(type: .custom) as UIButton
btn.backgroundColor = .blue
btn.setTitle("Button", for: .normal)
btn.frame = CGRect(x: 100, y: 100, width: 200, height: 100)
btn.addTarget(self, action: #selector(clickMe), for: .touchUpInside)
self.view.addSubview(btn)
}
#objc func clickMe(sender:UIButton!) {
print("Button Clicked")
}
func place() {
//do something to btn.
}

Read about variable scopes. In the question you have declared your button inside the method/function which restricts the scope of its usage within the method. When you declare the variable within the scope of the class/struct you can use it within other methods/functions.
let btn = UIButton(type: .custom)
override func viewDidLoad() {
super.viewDidLoad()
btn.backgroundColor = .blue
// .. other settings here
self.view.addSubview(btn)
}
#objc
func clickMe(sender:UIButton) {
print("Button Clicked")
}
func place() {
btn.backgroundColor = .red
}

Related

How to create a button programmatically with for loop in swift

I created buttons with for loop and i want to print button number when pressed to button. How can i do this?
for x in 0..<5 {
let button = UIButton(frame: CGRect(x: CGFloat(x) * view.frame.size.width + 10 , y: 40, width: view.frame.size.width - 20, height: 30))
buttonKontrol = x
print(buttonKontrol)
button.setTitle("Button", for: .normal)
button.backgroundColor = .white
button.setTitleColor(.black, for: .normal)
button.addTarget(self, action: #selector(btntapped), for: .touchUpInside)
scrollView.addSubview(button)
}
and objc func:
#objc func btntapped(_ sender: UIButton) {
print("button tapped")
}
Various ways to do that...
find the frame of the tapped button (not a good approach, but for your simple example it could work)
use the .tag property of the button
evaluate the .currentTitle property of the button
add the buttons to an array... on tap, use let buttonNumber = btnsArray.firstIndex(of: sender)
There are lots of ways, but a 'Swifty' way might be like this:
final class TargetAction {
let work: () -> Void
init(_ work: #escaping () -> Void) {
self.work = work
}
#objc func action() {
work()
}
}
class ViewController: UIViewController {
private var tas: [TargetAction] = []
override func viewDidLoad() {
super.viewDidLoad()
(0...4).forEach { x in
let button = UIButton(frame: CGRect(x: CGFloat(x) * 50 , y: 40, width: 44, height: 44))
button.setTitleColor(.black, for: .normal)
button.setTitle("\(x)", for: .normal)
let ta =
TargetAction {
print(x)
}
tas.append(ta)
button.addTarget(ta, action: #selector(TargetAction.action), for: .touchUpInside)
view.addSubview(button)
}
}
}

How to call / access a label in button action programmatically?

//This is the label
let changeLbl = UILabel(frame: CGRect(x: 20, y: 170, width: 300, height: 21))
self.view.addSubview(changeLbl)
//This is the button
let submitButton = UIButton(type: .system) // let preferred over var here
submitButton.addTarget(self, action: #selector(buttonAction) , for: UIControlEvents.touchUpInside)
self.view.addSubview(submitButton)
//and this is action of above button
func buttonAction(sender: UIButton!) {
}
I want to call the above label in the following button function? like
func buttonAction(sender: UIButton!) {
changeLbl.ishidden = true
// want to access label here, but it's not working this way.
}
If you want to Access changeLbl you need to define as instance variable like this way and give global scope inside the class.
class ViewController: UIViewController {
var changeLbl : UILabel!
var submitButton : UIButton!
override func viewDidLoad() {
super.viewDidLoad()
//This is the UILabel
changeLbl = UILabel(frame: CGRect(x: 20, y: 170, width: 300, height: 21))
self.view.addSubview(changeLbl)
//This is the button
submitButton = UIButton(type: .system) // let preferred over var here
submitButton.addTarget(self, action: #selector(buttonAction) , for: UIControlEvents.touchUpInside)
self.view.addSubview(submitButton)
}
//and this is action of above button
func buttonAction(sender: UIButton!) {
changeLbl.isHidden = true
}
}
changeLbl is a local variable. It's only visible in the scope of the method where the label is created.
If you don't want to use an instance variable – which is the normal way – and there is only one UILabel you can get the label from the subviews array
func buttonAction(sender: UIButton) {
if let changeLbl = self.view.subviews.filter({ $0 is UILabel}).first {
changeLbl.ishidden = true
}
}
If You want access label then declare it Globally.
Below Code for that:
class LabelDemo: UIViewController{
var changeLbl: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
changeLbl = UILabel(frame: CGRect(x: 20, y: 170, width: 300, height: 21))
changeLbl.backgroundColor = UIColor.black
self.view.addSubview(changeLbl)
//This is the button
let submitButton = UIButton(type: .system) // let preferred over var here
submitButton.backgroundColor = UIColor.green
submitButton.frame = CGRect(x: 50, y: 150, width: 50, height: 30)
submitButton.setTitle("hide", for: .normal)
submitButton.addTarget(self, action: #selector(buttonAction) , for: UIControlEvents.touchUpInside)
self.view.addSubview(submitButton)
}
func buttonAction(sender: UIButton!) {
if changeLbl.isHidden {
changeLbl.isHidden = false
}else{
changeLbl.isHidden = true
}
}
}

Stuck with adding target to button programmatically

I've created a UIButton and I want it to print some message when it's pressed.
So I did something like this:
In loadView()
button.addTarget(self, action: #selector(ViewController.pressButton(button:)), for: .touchUpInside)
A method:
func pressButton(button: UIButton) {
NSLog("pressed!")
}
But nothing happens when I click the button.
Add the button code in your viewDidLoad and it will work for you:
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
button.backgroundColor = UIColor.gray
button.addTarget(self, action: #selector(pressButton(button:)), for: .touchUpInside)
self.view.addSubview(button)
}
func pressButton(button: UIButton) {
NSLog("pressed!")
}
You don´t need to add ViewController.pressButton to selector, it´s enough with the function name.
Swift 4.x version:
let button = UIButton(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
button.backgroundColor = .gray
button.tag = 0
button.addTarget(self, action: #selector(pressButton(_:)), for: .touchUpInside)
self.view.addSubview(button)
#objc func pressButton(_ button: UIButton) {
print("Button with tag: \(button.tag) clicked!")
}
Swift 5.1 version:
let button = UIButton(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
button.backgroundColor = .gray
button.tag = 100
button.addTarget(self, action: #selector(pressButton), for: .touchUpInside)
self.view.addSubview(button)
#objc func pressButton(button: UIButton) {
print("Button with tag: \(button.tag) clicked!")
}
try this in Swift3!
button.addTarget(self, action: #selector(self.pressButton(button:)), for: .touchUpInside)
#objc func pressButton(button: UIButton) { NSLog("pressed!") }
Use the following code.
button.addTarget(self, action: #selector(FirstViewController.cartButtonHandler), for: .touchUpInside)
Your class name corresponds to FirstViewController
And your selector corresponds to the following function
func cartButtonHandler() {
}
In swift 3 use this -
object?.addTarget(objectWhichHasMethod, action: #selector(classWhichHasMethod.yourMethod), for: someUIControlEvents)
For example(from my code) -
self.datePicker?.addTarget(self, action:#selector(InfoTableViewCell.datePickerValueChanged), for: .valueChanged)
Just give a : after method name if you want the sender as parameter.
You mention that the addTarget call is in loadView(). Is this in your custom subview, of some kind, or the viewController?
From your selector, it's targeting a method in your ViewController class, but if the target for this action is the view itself, then it would make sense that the action is not going through.
If you declare your button in a viewController, and in viewDidLoad add this target as above, then the message should be printed as you're looking for. I believe you are "targetting" the wrong class with your action.
let cancelButton = UIButton.init(frame: CGRect(x: popUpView.frame.size.width/2, y: popUpView.frame.size.height-20, width: 30, height: 30))
cancelButton.backgroundColor = UIColor.init(patternImage: UIImage(named: cancelImage)!)
cancelButton.addTarget(self, action: #selector(CommentsViewController.canceled), for:.touchUpInside)
Add the button code in override func viewDidLoad() method
Make sure your action handler tagged with #IBAction like this:
#IBAction func pressButton(button: UIButton) {
print("pressed!")
}
Then it will work!

UIButton not working on a subview of UIWindow

I'm trying to create a custom one-button AlertViewController in Swift, I use window.addSubview() to show the AlertView, but when touch the button on the AlertView, the func buttonTapped() is not working, below is my code, please tell me what's wrong here, thanks.
MyAlertViewController.swift
class MyAlertViewController: UIViewController {
var button: UIButton!
var contentView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
setUp()
}
func setUp(){
contentView = UIView(frame: CGRectMake(0,0,200,300))
contentView.center = view.center
contentView.backgroundColor = UIColor.whiteColor()
contentView.layer.cornerRadius = 10
button = UIButton(type: .System)
button.frame = CGRectMake(50, 150, 100, 40)
button.setTitle("button", forState: UIControlState.Normal)
button.addTarget(self, action: #selector(buttonTapped(_:)), forControlEvents: UIControlEvents.TouchUpInside)
view.addSubview(contentView)
contentView.addSubview(button)
view.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.1)
view.userInteractionEnabled = true
}
func buttonTapped(sender: AnyObject?){
print("button tapped")
}
func show(){
let window = UIApplication.sharedApplication().keyWindow! as UIWindow
view.frame = window.bounds
window.addSubview(view)
}
}
ParentViewController.swift (is the rootViewController of my window)
class ParentViewController: UIViewController {
var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.whiteColor()
button = UIButton(type: .System)
button.frame = CGRectMake(110,269,100,30)
button.setTitle("show", forState: .Normal)
button.addTarget(self, action: #selector(buttonTapped(_:)), forControlEvents: .TouchUpInside)
view.addSubview(button)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func buttonTapped(sender: AnyObject?){
MyAlertViewController().show()
}
}
I found out if I change ParentViewController.swift as below, the button on the alert view can work correctly.
class ParentViewController: UIViewController {
var button: UIButton!
var vc: MyAlertViewController!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.cyanColor()
button = UIButton(type: .System)
button.frame = CGRectMake(110,269,100,30)
button.setTitle("show", forState: .Normal)
button.addTarget(self, action: #selector(buttonTapped(_:)), forControlEvents: .TouchUpInside)
view.addSubview(button)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func buttonTapped(sender: AnyObject?){
vc = MyAlertViewController()
vc.show()
}
}
But I intended to show this alert view each time the user get new messages,so it would show up at any time and on any ViewController , so I don't want to declare it in each ViewController, so How can I solve this?
TLDR;
You have to retain an instance of MyAlertViewController().
Change to this and it will work (as you've already done):
// keep some reference
var alert: MyAlertViewController?
func buttonTapped(sender: AnyObject?){
alert = MyAlertViewController()
alert?.show()
}
More explanation
The button.addTarget(self, ...) that is called inside MyAlertViewController does not retain self.
The last line of the doc of addTarget function said that:
// ... the action cannot be NULL. Note that the target is not retained.*
So there will be no self to send action to after leaving of this function:
func buttonTapped(sender: AnyObject?){
MyAlertViewController().show()
}
Another option,
is to keep self variable in MyAlertViewController:
// retain self manually
var mySelf: MyAlertViewController?
func setUp(){
...
// reference to self
mySelf = self
button.addTarget(mySelf, action: #selector(buttonTapped(_:)), forControlEvents: UIControlEvents.TouchUpInside)
}

clicking a on runtime created button crashes my ios app (swift)

I am a newby in ios development and I am facing the following problem.
I create a button at runtime in the viewDidLoad method:
class ViewController: UIViewController {
#IBOutlet weak var TestButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
println("start");
// Create Button at runtime
var button = UIButton.buttonWithType(UIButtonType.System) as UIButton
button.frame = CGRectMake(100, 100, 100, 50)
button.backgroundColor = UIColor.redColor()
button.setTitle("Test Button", forState: UIControlState.Normal)
button.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(button)
func buttonAction(sender:UIButton!)
{
println("Button tapped.")
}
}
When I press the button in the simulator the app stops at line :
class AppDelegate: UIResponder, UIApplicationDelegate {
of AppDelegate.swift
Does anyone have any idea why it doesn't output "Button tapped." ?
If I get a problem like this, how can I report the errormessage to someone else ? I mean I do not see any errorcode or stacktrace in XCode. Where to find this ?
Function not in viewDidLoad.
example:
class ViewController: UIViewController {
#IBOutlet weak var TestButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
println("start");
// Create Button at runtime
var button = UIButton.buttonWithType(UIButtonType.System) as UIButton
button.frame = CGRectMake(100, 100, 100, 50)
button.backgroundColor = UIColor.redColor()
button.setTitle("Test Button", forState: UIControlState.Normal)
button.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(button)
} // CLOSE
func buttonAction(sender:UIButton!)
{
println("Button tapped.")
}
}// CLOSE
You should extract your method for button outside your function like following:
class ViewController: UIViewController {
#IBOutlet weak var TestButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
println("start");
// Create Button at runtime
var button = UIButton.buttonWithType(UIButtonType.System) as UIButton
button.frame = CGRectMake(100, 100, 100, 50)
button.backgroundColor = UIColor.redColor()
button.setTitle("Test Button", forState: UIControlState.Normal)
button.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(button)
}
func buttonAction(sender:UIButton!)
{
println("Button tapped.")
}
}
Why is this you might ask? It is because you will register your event which is in scope of the function. When function ends your function for event is not there any more. Since, the chrash
Try this:
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton.buttonWithType(UIButtonType.System) as UIButton
button.frame = CGRectMake(100, 100, 100, 50)
button.backgroundColor = UIColor.greenColor()
button.setTitle("Test Button", forState: UIControlState.Normal)
button.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(button)
}
func buttonAction(sender:UIButton!)
{
println("Button tapped")
}
Also import UIKit

Resources