UIButton does not change title - swift

I want to change the buttons title on clicking the button:
func dispatchStatusButton(title title:String, backgroundColor:UIColor) {
self.btnDispatchStatus.setTitleWithoutAnimation(title.uppercaseString)
self.btnDispatchStatus.backgroundColor = backgroundColor
self.btnDispatchStatus.kern(2.0)
}
When I call the function:
// Set Button
self.dispatchStatusButton(title: "Inaktiv", backgroundColor: UIColor(red: 40.0/255.0, green: 51.0/255.0, blue: 57.0/255.0, alpha: 1.0))
Nothing happens and I have some feeling my kerning function is the reason, but I don't see why:
extension UIButton {
func setTitleWithoutAnimation(title:String?) {
UIView.setAnimationsEnabled(false)
setTitle(title, forState: .Normal)
layoutIfNeeded()
UIView.setAnimationsEnabled(true)
}
func kern(kerningValue:CGFloat) {
let attributedText = NSAttributedString(string: self.titleLabel!.text!, attributes: [NSKernAttributeName:kerningValue, NSFontAttributeName:self.titleLabel!.font, NSForegroundColorAttributeName:self.titleLabel!.textColor])
self.setAttributedTitle(attributedText, forState: UIControlState.Normal)
}
}

The problem is that self.titleLabel.text property gets updated in the following layout pass. That's why you set the title through setTitle(:forState:) function, and not to the label directly. In your kern function you reference to it when it is still not updated. Try the following:
func kern(kerningValue:CGFloat) {
let title = self.titleForState(.Normal) ?? "" // This gets the new value
let attributedText = NSAttributedString(string: title, attributes: [NSKernAttributeName:kerningValue, NSFontAttributeName:self.titleLabel!.font, NSForegroundColorAttributeName:self.titleLabel!.textColor])
self.setAttributedTitle(attributedText, forState: UIControlState.Normal)
}

Related

How to change font in textview dynamically with button tap in swift?

I created a textview like below and I add keyboard button for users can change the font. It is working but it changes whole text's font but I want to change fonts only after button clicking. Can you help about ?
func setKeyboard() { // this is for keyboard button
let bar = UIToolbar()
let flex = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: self, action: nil)
let font = UIBarButtonItem(image: UIImage(named: "icons8-image-80"), style: .plain, target: self, action: #selector(fontTapped))
bar.barTintColor = UIColor(displayP3Red: 30/255, green: 30/255, blue: 30/255, alpha: 1)
bar.sizeToFit()
writePost.inputAccessoryView = bar
}
// and this one is fontTapped function
#objc func fontTapped() {
if fontTag == 0 {
let attributedText = NSMutableAttributedString(string: writePost.text, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12)])
writePost.attributedText = attributedText
fontTag = 1
} else {
writePost.font = UIFont(name: "AvenirNext-DemiBoldItalic", size: 16)
fontTag = 0
}
}
To change the font / style for what the user types from now on, change the typingAttributes of the text view.
https://developer.apple.com/documentation/uikit/uitextview/1618629-typingattributes
You will be using the attributedText property of the UITextField like so:
https://medium.com/swift-india/multiple-font-style-for-uilable-text-using-nsattributed-string-3f121036a533
And probably build your attributed string in shouldChangeCharactersInRange() of the UITextFieldDelegate, in order to change the font of the incoming characters.
How shouldChangeCharactersInRange works in Swift?

How do you change the color of a UIButton when you are pressing it?

I am wondering how can you can change the color of a UIButton when it is pressed. By default, a UIButton has a faded blue when you press it. How do I change this from faded to, for example purple, when I press it. How do I do this in Swift 4? Is there some sort of property I can change?
Swift 4.2
use this extension for button:
extension UIButton {
func setBackgroundColor(_ color: UIColor, forState controlState: UIControl.State) {
let colorImage = UIGraphicsImageRenderer(size: CGSize(width: 1, height: 1)).image { _ in
color.setFill()
UIBezierPath(rect: CGRect(x: 0, y: 0, width: 1, height: 1)).fill()
}
setBackgroundImage(colorImage, for: controlState)
}
}
and simply usage:
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton()
button.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
button.setBackgroundColor(.red, forState: .normal)
button.setBackgroundColor(.blue, forState: .highlighted)
view.addSubview(button)
}
hope this make you smile :)
Use setTitleColor(_:for:) to set the title color (the first parameter) differently for the .normal and the .highlighted state (the second parameter).
See https://developer.apple.com/documentation/uikit/uibutton/1623993-settitlecolor
I think you can use setBackgroundImage function to archive that:
button.setBackgroundImage(UIImage(named: "PURPLE_IMAGE"), for: .highlighted)
You can set image for highlighted, selected, disable...etc
I know your question is to change the highlight background color, not the background image, but unfortunately it doesn't seems to have a direct way to do it. So my work around is to programmatically create an image of that color for the same effect (you may want to put it in UIImage extension):
let rect = CGRect(point: .zero, size: CGSize(width: 1, height: 1))
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
let context = UIGraphicsGetCurrentContext()
context!.setFillColor(color.cgColor)
context!.fill(rect)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
If you want to change UIButton background color with click you can simply use backgroundColor property as shown below:
#IBAction func btnTapped(_ sender: UIButton) { //sender type should be UIButton
sender.backgroundColor = UIColor.purple
}
and if you want to set title color on click you can use setTitleColor property as shown below:
#IBAction func btnTapped(_ sender: UIButton) {
sender.setTitleColor(UIColor.purple, for: .highlighted)
}
Use .backgroundColor for set Color; var button_isActive for button press, UIView.animate
var button_isActive: Bool = false
#IBAction func btn_Button(_ sender: UIButton) {
if button_isActive {
UIView.animate(withDuration: 0.2) {
sender.backgroundColor = UIColor.clear
}
} else {
UIView.animate(withDuration: 0.2) {
sender.backgroundColor = UIColor.purple
}
}
button_isActive = !button_isActive
}
Caveat: Even after setting the background color
btn.backgroundColor = .red
The color changing was not displaying, took a while to figure out that I need to change uibutton configuration from "Filled" to "Default"
You can try this for button color change
#IBAction func btnPress(_ sender: UIButton) {
DispatchQueue.main.async {
self.yourButton.backgroundColor = .purple
}
}

How to enable a button in different cases in swift?

I want to disable, and enable a button in different cases:
If the user comes to my share viewController the button will be disabled:
func handleShareAndAbortButton() {
shareButton.isEnabled = false
abortButton.isEnabled = false
let attributedShareButtonText = NSAttributedString(string: shareButton.currentTitle!, attributes: [NSAttributedString.Key.foregroundColor: UIColor(red: 0, green: 0, blue: 0, alpha: 0.2) ])
let attributedabortButtonText = NSAttributedString(string: abortButton.currentTitle!, attributes: [NSAttributedString.Key.foregroundColor: UIColor(red: 0, green: 0, blue: 0, alpha: 0.2) ])
shareButton.setAttributedTitle(attributedShareButtonText, for: .normal)
abortButton.setAttributedTitle(attributedabortButtonText, for: .normal)
}
The handleShareAndAbortButton will be called in viewDidLoad
If something changed (picture or text) I want to enable the button:
func imageDidChange() {
selectedText = postTextView.text!
let isText = selectedText
let isImage = selectedImage != nil
if isImage || isText != "Schreibe etwas..." && isText != nil {
shareButton.isEnabled = true
abortButton.isEnabled = true
let attributedShareButtonText = NSAttributedString(string: shareButton.currentTitle!, attributes: [NSAttributedString.Key.foregroundColor: UIColor(red: 255, green: 255, blue: 255, alpha: 1.0) ])
let attributedabortButtonText = NSAttributedString(string: abortButton.currentTitle!, attributes: [NSAttributedString.Key.foregroundColor: UIColor(red: 0, green: 0, blue: 0, alpha: 1.0) ])
shareButton.setAttributedTitle(attributedShareButtonText, for: .normal)
abortButton.setAttributedTitle(attributedabortButtonText, for: .normal)
}
}
I call the imageDidChange in viewWillAppear
Here I delete the placeholder after begin editing:
extension ShareViewController: UITextViewDelegate {
func textViewDidBeginEditing(_ textView: UITextView) {
if postTextView.textColor == UIColor.lightGray {
postTextView.text = nil
postTextView.textColor = UIColor.black
}
}
func textViewDidEndEditing(_ textView: UITextView) {
if postTextView.text.isEmpty {
postTextView.text = "Schreibe etwas..."
postTextView.textColor = UIColor.lightGray
}
}
}
When the user now enter some text, the placeholder "Schreibe etwas..." will be gone and the text will be also != nil. But its not working.
Update
I found out the problem. When I delete the isText != "Schreibe etwas..."
it works. But I need this. How can I compare to a String? If I don't have this code, the user is able to upload always with placeholder text.
Thanks in advance for your help!
You never call imageDidChange after you changed the text.
Use:
func textViewDidEndEditing(_ textView: UITextView) {
if postTextView.text.isEmpty {
postTextView.text = "Schreibe etwas..."
postTextView.textColor = UIColor.lightGray
}
imageDidChange()
}
I see that you’re using UITextField. You probably want to have just placeholder "Schreibe etwas...". So, in viewDidLoad or in Storyboard set placeholder of your TextField to "Schreibe etwas...". Then you don’t need TextField’s delegate methods for setting text and color of text in delegate methods.
Well, you need it, but not for this. You have to call imageDidChange in textFieldDidEndEditing
Now change declaring isText. You just passed reference for selectedText. Don’t do this, just check if there is text
let isText = !selectedText.isEmpty // don’t forget to !
also rewrite your conditions
if isImage || isText
... you don’t need to check if isText isn’tnil

Trouble Referencing UIButton using NSMutableAttributedString in Instantiated View Controller

As soon as my view controller loads, I am presented with a button (gray background with white font) that displays the text “Sto 1”. This is called in viewWillLayoutSubviews and the title is set using a NSMutableAttributedString. “Sto” is short for store.
For my application, I would like the user to be able to select the Sto 1 button and be able to store a number that is presented on a UILabel. I am able to grab the current number being displayed but I’m unable to update the text inside my Sto 1 button using NSMutableAttributedString. In other words I want to go from the button showing “Sto 1” to displaying some number (e.g., 12).
Thank you all for any help you may be able to provide me. I am still relatively new to Swift and I have been trying to resolve this issue over the past week.
import UIKit
class ViewController: UIViewController {
var fontConstant = CGFloat()
var someRandomNumberDisplayedOnAUILabel = String(12)
#IBOutlet weak var myButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillLayoutSubviews() {
fontConstant = 1
let myString = "Sto 1"
let myAttributes = [NSAttributedString.Key.foregroundColor : UIColor(red: 251/255.0, green: 251/255.0, blue: 251/255.0, alpha: 1.0), NSAttributedString.Key.font : UIFont.systemFont(ofSize: 10 * fontConstant)]
let mutableAttributedString = NSMutableAttributedString(string: myString, attributes: myAttributes)
myButton.setAttributedTitle(mutableAttributedString, for: .normal)
myButton.backgroundColor = UIColor(red: 94/255.0, green: 94/255.0, blue: 94/255.0, alpha: 1.0)
}
#IBAction func myButtonAction(_ sender: Any) {
let myAttributes = [NSAttributedString.Key.foregroundColor : UIColor(red: 0/255.0, green: 0/255.0, blue: 0/255.0, alpha: 1.0), NSAttributedString.Key.font : UIFont.systemFont(ofSize: 10 * fontConstant)]
let mutableAttributedString = NSMutableAttributedString(string: someRandomNumberDisplayedOnAUILabel, attributes: myAttributes)
myButton.setAttributedTitle(mutableAttributedString, for: .normal)
myButton.backgroundColor = UIColor(red: 251/255.0, green: 251/255.0, blue: 251/255.0, alpha: 1.0)
}}
Normally, you would use setTitle(:for:) to change the text on a UIButton. But since you're working with an NSMutableAttributedString you will need the setAttributedTitle(:for:) function. I think this might be what you're looking for:
myButton.setAttributedTitle(myNSMutableAttributedString, for: .normal)
Heads up, though. You might need to call this function for the different control states and not just .normal otherwise you might see different text for an instant as the button is highlighted. Here is a list of the control states.
EDIT:I would try referencing the sender in the IBAction instead of myButton. This might be a quick fix:
#IBAction func myButtonAction(_ sender: Any) {
let myAttributes = [NSAttributedString.Key.foregroundColor : UIColor(red: 0/255.0, green: 0/255.0, blue: 0/255.0, alpha: 1.0), NSAttributedString.Key.font : UIFont.systemFont(ofSize: 10 * fontConstant)]
let mutableAttributedString = NSMutableAttributedString(string: someRandomNumberDisplayedOnAUILabel, attributes: myAttributes)
guard let button = sender as? UIButton else {
print("Error: sender was not a button")
return
}
button.setAttributedTitle(mutableAttributedString, for: .normal)
button.backgroundColor = UIColor(red: 251/255.0, green: 251/255.0, blue: 251/255.0, alpha: 1.0)
}
EDIT #2:If you're losing the reference to your IBOutlet you might be able to work around that by assigning a selector to the button before you lose it. Try this:
override func viewDidLoad() {
super.viewDidLoad()
// Add the action to the button rather than holding on to the IBOutlet
myButton.addTarget(self, action: #selector(RideInProgressViewController.myAction(sender:)), for: .touchUpInside)
}
#objc private func myAction(sender: Any) {
guard let button = sender as? UIButton else {
print("Error: sender was not a button")
return
}
let myAttributes = [NSAttributedString.Key.foregroundColor : UIColor(red: 0/255.0, green: 0/255.0, blue: 0/255.0, alpha: 1.0), NSAttributedString.Key.font : UIFont.systemFont(ofSize: 10 * fontConstant)]
let mutableAttributedString = NSMutableAttributedString(string: someRandomNumberDisplayedOnAUILabel, attributes: myAttributes)
button.setAttributedTitle(mutableAttributedString, for: .normal)
button.backgroundColor = UIColor(red: 251/255.0, green: 251/255.0, blue: 251/255.0, alpha: 1.0)
}

Swift UIButton .setTitle not working

I am programmatically creating a set of buttons on my VC. I am adding a target for the buttons when creating them and in the function that gets called I am changing the background image and trying to remove the title. However, the title is not changing but the background image is changing which doesn't make sense to me.
func createButton(xPos: Int, yPos: Int, width: Int, height: Int, buttonIndex: Int) -> UIButton {
var button = UIButton()
button.frame = CGRect(x: xPos , y: yPos, width: width, height: height)
button.userInteractionEnabled = true
button.layer.masksToBounds = true
var buttonImage = UIImage(named: "Display_Icon")
button.tag = buttonIndex
button.setBackgroundImage(buttonImage, forState: UIControlState.Normal)
button.setTitle("\(buttonIndex)", forState: UIControlState.Normal)
var titleColor = UIColor(red: 0.0, green: 104/255.0, blue: 178/255.0, alpha: 1.0)
button.setTitleColor(titleColor, forState: UIControlState.Normal)
button.addTarget(self, action: "screenSelected:", forControlEvents: UIControlEvents.TouchUpInside)
return button
}
func screenSelected(button: UIButton!) {
if hasError { hasError = false; return }
let screenIndex = button.titleLabel!.text!
if contains(buttonsSelectedArray, screenIndex) {
return
}
buttonsSelectedArray.append(screenIndex)
var buttonImage = UIImage(named: "DisplaySelected_Icon")
button.setBackgroundImage(buttonImage, forState: UIControlState.Normal)
button.setTitle("", forState: UIControlState.Normal)
var titleColor = UIColor.clearColor()
button.setTitleColor(titleColor, forState: UIControlState.Normal)
Try this,
Problem that u add target button in old method(Obj-c)
func createButton(xPos: Int, yPos: Int, width: Int, height: Int, buttonIndex: Int) -> UIButton {
....
....
button.addTarget(self, action: #selector(UIViewController. screenSelected(_:)), for: UIControlEvents.touchUpInside)
return button
}
#IBAction func screenSelected(button: UIButton!) {
if hasError { hasError = false; return }
let screenIndex = button.titleLabel!.text!
if contains(buttonsSelectedArray, screenIndex) {
return
}
buttonsSelectedArray.append(screenIndex)
var buttonImage = UIImage(named: "DisplaySelected_Icon")
button.setBackgroundImage(buttonImage, forState: .normal)
button.setTitle("", forState: .normal)
var titleColor = UIColor.clearColor()
button.setTitleColor(titleColor, forState: .normal)
}
You need to set your button title like this
button.setTitle("Button Title Here", for: UIControlState.normal)
IOS no longer supports using
button.titleLabel?.text= "Button Title"
because you are required to set your title with its UIControlState which is either selected, normal, highlighted or whatever it is.
Please see the documentation from this https://developer.apple.com/reference/uikit/uibutton/1624018-settitle?language=objc