Set custom attribute on button - ios

How can i set custom attributes on an button that is programmatically created?
I have this code to create an button:
var btn = UIButton(frame: CGRectMake(CGFloat(7 + add), 565, 39, 55))
btn.setTitle(String(Array(shuffledWord)[i...i]), forState: UIControlState.Normal)
btn.addTarget(self, action: "btnPressed:", forControlEvents: UIControlEvents.TouchUpInside)
btn.tag = 7 + add;
I can give some value to .tag but are there more thing like that? Can i create custom attributes to set on the button?

If you need custom properties on a class that doesn't belong to you, subclass it and use the subclass instead.
class MyCoolButton : UIButton {
var myCoolProperty : String = "coolness"
}
And later:
var btn = MyCoolButton( // ...

First I would start by looking at the class reference here
What attributes are you directly looking to change about the button? You can set it's title color, font, border color/width, corner-radius etc.
A lot of these can be mutated by accessing the button's layer as in
btn.layer.borderWidth = 2.0 and things of that nature.
EDIT: If you are looking to add custom features or store some properties then I would refer to Matt's answer about subclassing.

Related

Add Button Tag Buttons inside SearchBar

I want to implement when I start editing inside search bar, then list would appear below the searchbar and I would select multiple values from list and when I want to select any text It would be add inside my search bar or textfield like button like this image below
this is example from stack overflow, so please guide me how to implement this I have no idea about this implementation, you can refer also third party library also and if you can help me with code. Thanks
may it will works
i suggested to use textfield as search engine
write code inside add button
let button = UIButton(type: .custom)
button.setTitle("name", for: UIControlState.normal)
button.frame = CGRect((x: CGFloat(txt.frame.size.width - 25), y: CGFloat(5), width: CGFloat(25), height: CGFloat(25)))
button.addTarget(self,action: #selector(action), for: .touchUpInside)
textField.rightView = button
textField.rightViewMode = .always
use array to save the values

How to change titleTextAttributes of UIBarButtonItem after it's pressed?

I have a navigation bar with several UIBarButtons that I initially display with an alpha of 0.5, and would like to display with an alpha of 1 after pressed. I am storing these attributes in normalAttributes and highlightedAttributes.
I set up the buttons in the following manner:
colorButton = UIBarButtonItem(title: "Colors", style: .plain, target: self, action: #selector(showColors))
colorButton.setTitleTextAttributes(normalAttributes, for: .normal)
colorButton.setTitleTextAttributes(highlightedAttributes, for: .selected)
This leads to the button briefly switching to the highlightedAttributes, which is expected. However, within the button's action showColors I then perform the following:
textButton.setTitleTextAttributes(highlightedAttributes, for:[])
I have also tried using .normal instead of []. Neither method seems to have any sort of effect on the button. Any help with this would be really appreciated.
The easiest way to accomplish this I can think of is using a custom view. Meaning, create a separate UIButton and make a reference to it in your class (e.g., let yourButton = UIButton()). Initialize your bar button item with UIBarButtonItem(customView: yourButton) and then use it however you want to.
Just note that you'll need to add your action/target pair on yourButton, not on the bar button item. Then in your action handler, showColors in your case, you can change the appearance of yourButton.
You can either toggle alpha directly or if it's just text we're talking about, you could do:
yourButton.setTitleColor(yourColor, for: .normal)
and
yourButton.setTitleColor(yourColorHalfAlpha, for: .selected).
Then in your showColors, just call yourButton.isSelected = !yourButton.isSelected to toggle the appearance.
A UIButton contains a UILabel as the titleLabel property. Just set its attributes the usual way instead of setting them via the button’s pass-through functions.

Swift / iOS - UIButton Sender with more information

Lets say you have a calculator you're building for iOS in Swift. When a user taps an operation (division, addition, subtraction, etc) I'd like to avoid having a separate method to handle each.
Instead, i'd prefer to have a factory which, based on the sender, determines the correct OperationType sub-class to use (Subtraction, Multiplication, etc)
My question is: is it proper practice to store information directly on the UI Button in Xcode? For instance, on the Addition button (+), if I tagged it with Addition, I could then use that information to load the Addition class.
Similarly, for each digit, i would prefer to have one function which handles a user pushing any digit. However, to determine the sender, it seems somewhat sloppy to use sender.title, since it binds the visual title of the digit, to the code. Is it then appropriate to provide tags to deal with this, or is there another system of handling this?
You can certainly do that, and sometimes it makes for a clean design. View objects have a tag property (an Int.) You can put a switch statement on your action method(s) that switches on the tag value. Generally you should use tag values starting from 1 or greater, since 0 is the default tag value.
If you need more than an integer value you can either save your values into an array that you index into with the tag value or you can use associative storage to actually store objects attached to your buttons. Do a search on "Cocoa associated objects" for more information on that technique. Or you can take a look at a demo project I put on github: https://github.com/DuncanMC/AssocitiveStorageDemo (Written in Objective-C, but the technique is the same in Swift)
override func viewDidLoad() {
super.viewDidLoad()
let button1 = UIButton(frame: CGRect(x: 0, y: 0, width: 200, height: 200));
let button2 = UIButton(frame: CGRect(x: 0, y: 250, width: 200, height: 200));
button1.backgroundColor = UIColor.greenColor();
button2.backgroundColor = UIColor.yellowColor();
button1.addTarget(self, action: "buttonTaped:", forControlEvents: .TouchUpInside);
button2.addTarget(self, action: "buttonTaped:", forControlEvents: .TouchUpInside);
button1.tag = 0;
button2.tag = 1;
self.view.addSubview(button1);
self.view.addSubview(button2);
}
func buttonTaped(button:UIButton){
switch(button.tag){
case 0:
print("button 1 taped");
break;
case 1:
print("button 2 taped");
break;
default:
break;
}
}
You can use the tag property
func buttonClicked(sender:AnyObject) {
let button = sender as! UIButton
if button.tag == 0 {
...
}
else if button.tag == 1 {
...
}
}

Creating Default-Style UIButton in Swift

When I create a UIButtonin Swift, e.g. by
let aButton = UIButton()
aButton.setTitle("Title", forState: UIControlState.Normal)
it seems like I'm not getting the same button style as I would get if I added a button in Interface Builder. Specifically, the title color is white instead of the default "tint color", leaving the button invisible. Now I want this button to look like any other button, so I don't want to specify my own colors.
Setting the normal (not pressed) state can be done with:
aButton.setTitleColor(self.tintColor, forState: UIControlState.Normal)
So far, so good. But the text color does not change when the button is pressed. I guess, for that I need
aButton.setTitleColor(/* somehting here */, self.tintColor, forState: UIControlState.Highlighted)
Ideally without hardcoding the color, what do I need to substitute above to get the default pressed button color? Or is there even a simpler way to just create a UIButton with default style?
In order to declare a button of the same (default) style as in the storyboard/interface builder, use the following code to instantiate it:
let aButton = UIButton(type: .system)
Otherwise the button is of type custom.
You can read about the various button types here.

UIButton in Swift is not registering touches

I'm trying to create a UIButton using Swift. It compiles fine and I can see my button in the simulator, but when I click it, nothing happens. This is the code I am using:
let settings = UIButton()
settings.addTarget(self, action: "touchedSet:", forControlEvents: UIControlEvents.TouchUpInside)
settings.setTitle("Settings", forState: .Normal)
settings.frame = CGRectMake(0, 530, 150, 50)
scrollView.addSubview(settings)
In the same class, here is the function 'touchedSet':
func touchedSet(sender: UIButton!) {
println("You tapped the button")
}
I'm using the simulator as I don't have an iOS 8.0 device, could that be the problem?
Thanks!
I see it is an old question but I just faced very similar problem yesterday. My buttons were highlighted on touch but not firing the action.
I have two view controllers. One view covers the others view and button is on the top view.
eg.
Rootviewcontroller has back view
Topviewcontroller has top view
The button on top view does not call the action if I don't add the topviewcontroler as childviewcontroller of the rootviewcontroller. After adding the topviewcontroller as childviewcontroller it started to working.
So in short: just try to add the view controller of buttons superview as childviewcontroller to the parent views viewcontroller with the following method
func addChildViewController(_ childController: UIViewController)
Selectors are a struct that have to be created.
Do it this way...
Updated for Swift 4
settingsButton.addTarget(self, action: #selector(showSettings), for: .touchUpInside)
That should do it.
For anyone else doing manual view layout running into this issue, you might have defined your subview like such:
let settingsButton: UIButton = {
let button = UIButton(type: .system)
// do some more setup
button.addTarget(self, selector: #selector(openSettings), for: .touchUpInside)
return button
}()
The error lies with the fact that you are adding a target and passing self before it is actually available.
This can be fixed in two ways
Making the variable lazy and still adding the target in the initialization block:
lazy var button: UIButton = {
let button = UIButton(type: .system)
// since this variable is lazy, we are guaranteed that self is available
button.addTarget(self, selector: #selector(openSettings), for: .touchUpInside)
return button
}()
Adding the target after your parent view has been initialized:
init() {
self.settingsButton = .init(type: .system)
super.init(frame: .zero)
self.settingsButton.addTarget(self, selector: #selector(openSettings), for: .touchUpInside)
}
In the simulator, sometimes it doesn't recognise the selector. There is a bug it seems. I just changed the action name (selector), and it worked.
let buttonPuzzle:UIButton = UIButton(frame: CGRectMake(100, 400, 100, 50))
buttonPuzzle.backgroundColor = UIColor.greenColor()
buttonPuzzle.setTitle("Puzzle", forState: UIControlState.Normal)
buttonPuzzle.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
buttonPuzzle.tag = 22;
self.view.addSubview(buttonPuzzle)
Selector Function is Here:
func buttonAction(sender:UIButton!)
{
var btnsendtag:UIButton = sender
if btnsendtag.tag == 22 {
//println("Button tapped tag 22")
}
}
I have had this problem when parent view of my button has isUserInteractionEnabled == false. All subviews will have the same userInteraction as their parent view. So I have just added this line parentView.isUserInteractionEnabled = true and the problem disappeared. Hope this helps someone.
For those who are also stuck in the tutorial:
I ran in to the same problem, when I was following Apple's "Start Developing iOS Apps (Swift)". It turned out that I had overlooked these code lines in the tutorial:
override var intrinsicContentSize : CGSize {
return CGSize(width: 240, height: 44)
}
Adding them to my RatingControl fixed the problem.
I had a similar problem when i had a subViewController with buttons and tapHandlers to match, and I wanted to place this to a stack in a separate superViewController..
This cause none of the tapHandlers to to trigger, and the solution was to instead of only using addArrangedSubview(subViewController.view), I also used addChildViewController(subViewController) in the superview to allow the childViewController to continue to operate as a viewController and not just a view.
So you should use following line
settings.userInteractionEnabled = true
Old question, but thought I'd give some help to other looking for this issue. First off, I'm not entire sure this is correct so please correct me if I'm wrong.
But if you set the selector wrongly the application would crash when you press the button since it's subscribed to a selector which doesn't exist. Which means that your selector is working. My guess is that something else is blocking the touch event, assuming UIButton.enabled = true and UIButton.userInteractionEnabled = true. Usually you could check this by long pressing the button and see if it hits. If it does then you have a UIGestureRecognizer added somewhere which takes up the hits first. Could also be the UIScrollView which is delaying the touch input (there's a checkbox for this in the Inspector).
Hope this helps someone, and hope it's accurate.
I had the same issue when implementing UIButton and SearchBar on container view(UIView).
In my case, the cause was the constraint issue. Constraint to searchBar had issue and because of this, function set had never been called.
You can see if there's any from "Debug View Hierarchy" button. (constraint problem is shown as purple warning)
(env: iOS12, xcode10.1)
Interestingly enough, I just ran into the same issue on the very latest versions of iOS/Xcode (v12.4 / v10.3). Turns out the issue for me was a LayoutConstraint! No joke. I had a leading label with the uiSwitch to the right, and found that I needed to change the constraints between the two such that it wasn't a fixed constant value of 8 points (Label-8-Switch-0-|).
As soon as I changed this to a ">=" the Switch was able to change states between on/off. Laughably, it's almost like it wasn't able to change because it needs "room" (that apparently varies) to make the change with.
Not sure, but file it away as one of those "hummmm?" items in your memory.
One other item (that really shouldn't matter, frankly) is the valueChanged and tappedUpInside were both not firing (true on both an actual handset and on the simulators). Also, they were hooked up through a storyboard. But, this shouldn't matter as far as I know.
I had the same issue. The problem was the view had top constraint, but not left/right and height constraints. So, the view was shrinking to 1x1 and it was not passing the touch event to children.
By adding more constraints, the children now getting the touch event and working ...
let guide = view.safeAreaLayoutGuide
viewHeader.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
viewHeader.rightAnchor.constraint(equalTo: guide.rightAnchor).isActive = true
viewHeader.leftAnchor.constraint(equalTo: guide.leftAnchor).isActive = true
let heightConstraint = NSLayoutConstraint(item: viewHeader,
attribute: NSLayoutConstraint.Attribute.height,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: nil,
attribute: NSLayoutConstraint.Attribute.notAnAttribute,
multiplier: 1,
constant: 44)
viewHeader.addConstraints([heightConstraint])
Old question, but I also found myself stuck with an unresponding button. I simply changed my initialisation from
let button = UIButton(frame: .zero)
to
let button = UIButton(type: .system)
I can see only one problem: You have to set the action with Selector as following:
settings.addTarget(self, action: Selector("touchedSet:"), forControlEvents: UIControlEvents.TouchUpInside)
Don't forget to insert : if you need to pass parameters to the function.
You said within the same class. Make sure that the button code itself is in the viewDidLoad() and the action be outside of it but inside the class if you are working with a view.
The problem with that tutorial from Apple is the way they put the UIView (RatingControl) inside the StackView, which is incorrect. The UIView (RatingControl) should be outside of the StackView. So, the solution is:
1. Drag the UIView (RatingControl) outside of the StackView
2. Set the constraints for the new position of the RatingControl
- Leading margin to the Container equal zero
- Trailing margin to the Container equal zero
- Top margin to the StackView equal zero
With this new constraints, now the RatingControl will have the same with as the Container, no matter what is the device screen size, and always will be just behind of the StackView where the photo selector will appear.
I hope this help you guys.
Make sure you link you button with your IBOutlet instance variable in your code if you're using storyboard.
I've found similar example for Swift 2 and adapted for Swift 3. Tested it is working very well. I hope it helps.
// http://lab.dejaworks.com/ios-swift-3-playground-uibutton-action
// Trevor D. Beydag
import UIKit
import PlaygroundSupport
class Responder : NSObject {
func action() {
print("Button pressed!")
}
}
let containerView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 300.0, height: 600.0))
PlaygroundPage.current.liveView = containerView
let responder = Responder()
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
button.backgroundColor = UIColor.green
button.setTitle("TEST", for: .normal)
button.addTarget(responder, action: #selector(Responder.action), for: .touchUpInside)
containerView.addSubview(button)
I had changed the height and width constraints to 0, for some reason I needed to do this so it showed correctly on a multipurpose view for one use case, the buttons were visible but the touch stopped working.
In my case, I had a transparent UIView above the UIButton in the view hierarchy, which is why when I was "clicking on the UIButton", I was actually clicking on the transparent UIView on top of it.
Sending the transparent UIView back using parentUIView.sendSubviewToBack(transparentUIView) worked for me, because after doing this the UIButton came on top of the view hierarchy. Click on the "Debug View Hierarchy" button in Xcode to check if the UIButton is on top or not.
If you're using Autolayout to build your UI, make sure to declare all your constraints in your view and parent views.
Some times we forget to set all of them and the system complains about it, drawing your UI but not responding correctly in your touch events.
In my case, i’ve forgot to set my bottom constraint in my view so i’m here to set this comment as a reminder.
When a view like a button is placed next to another view like an image view etc. especially if if the image view is on top of another view Xcode sometimes thinks that your button is underneath that image view even though it is not. Sometimes you need to clear all the constraints and reset all constraints in order for the button to work.

Resources