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
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 have a custom UIButton but I am not able to make changing background or text color based on a quick tap. If something works, it's only on long press:
buton.isUserInteractionEnabled = true
buton.setTitle("text_normal", for: .normal)
buton.setTitle("text_highlighted", for: .highlighted)
buton.setTitle("text_selected", for: .selected)
buton.setTitle("text_focused", for: .focused)
The only text I can get is "text_highlighted" after holding the button ~1 second. But nothing happens on short tap.
But the action is triggered correctly:
let tap2 = UITapGestureRecognizer(target: self, action: #selector(handleTap))
buton.addGestureRecognizer(tap2)
#objc func handleTap(sender: UITapGestureRecognizer) {
print("click")
}
What I tried:
Adding custom
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
...
which is also triggered later. And combining with tocuhesEnded didn't change the color temporarily as well (maybe it was too quick).
I can't use UIButton(type: .system) as well - it's not system styled button.
Similar as with changing text this is not working as well:
self.setTitleColor(UIColor.gray, for: .normal)
self.setTitleColor(UIColor.yellow, for: .selected)
self.setTitleColor(UIColor.yellow, for: .highlighted)
self.setTitleColor(UIColor.yellow, for: .focused)
I can see yellow only when long pressed. I am looking for something like this, but it needs to work on quick tap as well.
Custom button is modifying layoutSubviews(), but not colors. Custom button contains default image and label. Whole button has rounded corners. But overall nothing special is in there.
I am not using any storyboard or XIB - everything is in Swift 4 programatically.
The button is supposed to lead to another ViewController, but I want to see the immediate feedback on click. Something like when created from storyboard: https://youtu.be/lksW12megQg?t=3m25s - not even simple alpha change works for me right now.
check isselected property of uibutton if button is selected then change the background color of button
Jen Jose was right - there was a problem with my parent class which was 'eating up' my touches. I confirmed this when moving it to different ViewController + I had the same issue with table, which couldn't handle touch events (https://stackoverflow.com/a/9248827/1317362)
EDIT:
To be precise - this button was in a UIScrollView.
Adding scrollView.delaysContentTouches = NO; solved the issue completely.
Details: https://stackoverflow.com/a/16650610/1317362
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 not able to understand why the addTarget in my UIButton is not working in a specific case.
So, there is a UITableViewCell where I create a button programmatically, like:
let myClickButton : UIButton = {
let button = UIButton()
button.setTitle("Hit Test", for: .normal)
button.tintColor = UIColor.white
button.addTarget(self, action: #selector(printMessage), for: .touchUpInside)
button.isUserInteractionEnabled = true
return button
}()
And, there is also the function in my UITableViewCell class that the button was supposed to be calling:
func printMessage(){
print("button was clicked")
}
However, the printMessage function is never called and there is no error in the console. Could you help me understand what is the problem on this case? It seems to be the problem of being in a UITableViewCell as I definitely tested it on a regular viewController and it worked fine.
Thanks a ton!
Depending on where the closure for the button is, I would try setting the target AFTER the UITableViewCell has been instantiated. Other than that, I'm not sure what the problem is without seeing more code.
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