In my view controller's viewDidLoad, I added a button:
let tutorialButton = UIButton.buttonWithType(UIButtonType.System) as! UIButton
tutorialButton.frame = CGRectMake(0, (UIScreen.mainScreen().bounds.size.height/4)*3, UIScreen.mainScreen().bounds.size.width, 20)
tutorialButton.titleLabel?.textAlignment = NSTextAlignment.Center
tutorialButton.backgroundColor = UIColor.clearColor()
tutorialButton.setTitle("View Quick Tutorial", forState: UIControlState.Normal)
tutorialButton.addTarget(self, action: "giveTutorial:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(tutorialButton)
The button appears where I want it and that part works great. But after it has served it's purpose and I no longer want it visible, how do I remove the button from the view? I've researched that it's usually done like this:
buttonName.removeFromSuperview
However, when I type in buttonName, it does not recognize the button. I guess because there's no IBOutlet. So then what code can I stick in a method that'll get this button removed?
Declare a class variable (not an IBOutlet) to hold the button reference.
var tutorialButton : UIButton?
Populate button in code and remove with
tutorialButton?.removeFromSuperview
My problem turned out to be not in what code I typed, but where I typed it. Because I wanted the view to be added upon load, I added the whole chunk of code to my viewDidLoad. However, this line did not belong there:
let tutorialButton = UIButton.buttonWithType(UIButtonType.System) as! UIButton
By declaring tutorialButton within the viewDidLoad, I caused it to not be accessible/reference-able outside of the viewDidLoad. To fix this, all I had to do was move that line outside of the viewDidLoad.
let tutorialButton = UIButton.buttonWithType(UIButtonType.System) as! UIButton
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
...
This is a key thing to take note of if you plan to edit or remove the view later, from a method other than the viewDidLoad. Now that I made the change, I can add the removeFromSuperview call to a buttonPress and it works great:
tutorialButton?.removeFromSuperview
Related
My senior was reviewing my code and he found that I have used UIButton addTarget method like this
override func viewDidLoad() {
super.viewDidLoad()
self.btnAccount.addTarget(self, action: #selector(Accounts(_:)), for: .touchUpInside)
}
Now he is saying that you should not use addTarget in viewDidLoad it will take time(kind of memory management thing I didn't get it) to load view controller but I didn't find it relevant
that's why I am asking this question did I made some mistake by doing this should I always make actions
I didn't hear of that and even if it is true, you should never try to do premature optimization on your app. UIButton is a UIControl object, which follows an event-listener pattern, which is often implemented with a hashmap (NSDictionary in Objective-C) of targets ('aka' Listeners or Observers) and it is not very time-consuming operation.
I personally prefer to setup all UI component right at the beginning:
lazy var btnAccount: UIButton = {
let btn = UIButton
// setup button's appearance
btn.addTarget(self, action: #selector(Accounts(_:)), for: .touchUpInside)
return btn
}()
P.S. Please ask him about the source of the fact and let me know.
I am trying to make my button, when tapped, to push to a new View Controller. I've tried many different ways but it won't trigger the function that I have it linked to. I also checked the 3D stack view of my layers and the button is on top and clickable, even when I check the background color, it's not being covered by anything else.
Does anyone have any ideas to what I am doing wrong?
For now I am trying to make the button print out the sentence in the console, however whenever I press it, the string doesn't pop up, so I haven't bothered to connect it to the view controller yet.
Also, I am coding this app without storyboards.
Here is my code below.
It is under the MainPageCell class declared as a UICollectionViewCell
private let playButton: UIButton = {
let button = UIButton()
button.setTitle("", for: .normal)
button.backgroundColor = .clear
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(MainPageCell.buttonTapped), for: .touchUpInside)
return button
}()
#objc func buttonTapped() {
print("I PRESSED THE BUTTON")
}
This line is wrong:
button.addTarget(self, action: #selector(MainPageCell.buttonTapped), for: .touchUpInside)
You cannot assign self as the action target in a property declaration initializer, because the instance designated by self does not exist yet. There is no error or warning (I regard that as a bug), but the action method is never called.
Move that assignment elsewhere and rewrite it, like this:
self.playButton.addTarget(self, action: #selector(MainPageCell.buttonTapped), for: .touchUpInside)
Maybe try defining your button action under the UIView Class, I've had a problem like that before, only worked when i linked it to the View Class, Good luck
Within my app i'm trying to back a UIButton, i just want it to print "this is a test" When i press the button it does the classic button animation, however there is nothing printed in the console.
var tbutton: UIButton = {
let button = UIButton(type: .system)
button.frame = CGRect(x: 40.0, y:400.0, width: 300.0, height: 300.0)
let image = UIImage(named: "backb")
button.setBackgroundImage(image, for: .normal)
button.addTarget(self, action: #selector(dothings), for: .touchUpInside)
return button
}()
#objc func dothings(){
print("this is a test")
}
I then add the button into view with:
view.addSubview(tbutton)
Is there a section of code i'm missing, or have i coded something wrong?
You shouldn't initialize your button in that way.
Quoting the Apple documentation from Setting a Default Property Value with a Closure or Function:
If you use a closure to initialize a property, remember that the rest of the instance has not yet been initialized at the point that the closure is executed. This means that you cannot access any other property values from within your closure, even if those properties have default values. moreover:
You also cannot use the implicit self property, or call any of the instance’s methods, hence the problem is here:
button.addTarget(self, action: #selector(dothings), for: .touchUpInside)
so to fix the issue you should move the button initialization (or move the addTarget) after your ViewController is fully initialized (eg: viewDidLoad).
Another way to fix the issue, assuming you are using such button only after viewDidLoad, is to define it as a lazy var:
A lazy stored property is a property whose initial value is not calculated until the first time it is used
I'm trying to create a custom class that creates a button. I'm having trouble adding a target to that button inside it's class. This is my code
class SelectButton{
var button:UIButton = UIButton()
init(button_frame: CGRect, button_title: String, connected: [UIButton]?){
self.button.frame = button_frame
self.button.setTitle(button_title, for: UIControlState.normal)
self.button.addTarget(self, action:#selector(self.buttonPressed), for: .touchUpInside)
}
func construct() -> UIButton {
return self.button
}
#objc func buttonPressed() {
print("Button Clicked")
}
}
The problem is that I can't connect an action on button click. This works if it's used outside my class but not inside.
Usage of the class
let test = SelectButton(button_frame: CGRect(x:50, y:50, width: 250, height:150), button_title: "Test button", connected: nil).construct()
self.view.addSubview(test)
When someone taps the button, usually you want something to happen somewhere else in your app (like in one of your view controllers or in some other UI element). The way the IBAction is set up right now, you have it so that something will trigger or happen within the button itself when someone taps on it. If you want to handle a button tap programmatically instead of ctrl dragging from the button into the view controller, you can do it this way if you prefer. First, add this code into the view controller:
#IBAction func buttonPressed(sender: UIButton) {
}
Then you can either add the selector programmatically by adding this method into your view controller:
myButton.addTarget(self, action:self.buttonPressed(sender), for: .touchUpInside)
Or by going to the connections inspector and dragging from the touch up inside over to the IBAction dot in your view controller code. Also, as someone else pointed out in the comments you should make your button inherit from UIButton by adding this to your class declaration:
class SelectButton: UIButton {
. . .
}
Nothing is holding a strong reference to your SelectButton instance, so as soon as the function that creates test exits, that instance is released.
The button itself is retained because you have added it as a subview. Therefore, it is still visible but there is no longer an object to respond to the action.
You either need to use an instance property rather than a local variable for test, or, preferably have SelectButton inherit directly from UIButton
I am building my first iOS-App using Swift and I am stuck.
I have a CollectionView and inside one of the Cells there is a button and an imageView.
What should happen is: I click the button and the imageView shows another picture.
I already created a CellSubClass but I just don't get how to use it.
Can anyone PLEASE help me?
Write an action method for your button inside your cellClass like this:
func changeImage
{
var image: UIImage = UIImage(named: "your image name")!
yourImageView.image = image
}
Don't forget to "assign" this method to your button either in initialization method for the cell (awakeFromNib is also called when cell is started or oyu could write your own custom init method). You can also do it by using IBAction from storyboard (Simple dragging and clicking).
But programmatically it is done Like this if you use the awakeFromNib approach:
override func awakeFromNib() {
super.awakeFromNib()
yourButton.addTarget(self, action: "changeImage", forControlEvents: UIControlEvents.TouchUpInside)
}
To learn how to create IBAction using storyboard, read here.