How to enable a button in different cases in swift? - 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

Related

UIAlertController Alert action TextField need to be resized-error

Getting this error...
[LayoutConstraints] Changing the translatesAutoresizingMaskIntoConstraints property of a UICollectionViewCell that is managed by a UICollectionView is not supported, and will result in incorrect self-sizing. View: <_UIAlertControllerTextFieldViewCollectionCell: 0x7fe6a9f26000; frame = (0 0; 270 24); gestureRecognizers = <NSArray: 0x60000098edc0>; layer = <CALayer: 0x6000007c5cc0>>
From this...
func saveText()
{
let ac = UIAlertController(title: "NAME IT", message: nil, preferredStyle: .alert)
ac.addTextField()
let submitAction = UIAlertAction(title: "SAVE", style: .default)
{
[unowned ac] _ in
let answer = ac.textFields![0]
if answer.text!.count < 1
{
self.view.backgroundColor = .red
}
else
{
self.view.backgroundColor = .green
}
}
ac.addAction(submitAction)
present(ac, animated: true)
}
I have played around with this for a while, I have tried to figure out if I can add my own textfield to use it too...
func addTextField()
{
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
}
But no luck
I need to remove this error.
Thanks in advance
Oh, this didn't help at all
https://www.hackingwithswift.com/example-code/uikit/how-to-add-a-uitextfield-to-a-uialertcontroller
Thanks for trying to help, couldn't waste more than a day waiting for a solution so I spent two hours on a workaround instead.
I figured it would be mean of me not to share...
OR rather nice that I spent the extra 20 mins to share my workaround.
If anyone plays hero and wants to edit this, I am happy to delete the answer.
import UIKit
class ViewController: UIViewController
{
let textFieldView = UIView()
let textFieldLabel = UILabel()
let textFieldField = UITextField()
let textFieldButton = UIButton()
let WhiteUIColour: UIColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
let LightGreyUIColour: UIColor = #colorLiteral(red: 0.921431005, green: 0.9214526415, blue: 0.9214410186, alpha: 1)
let DarkBlueUIColour: UIColor = #colorLiteral(red: 0.01680417731, green: 0.1983509958, blue: 1, alpha: 1)
let MediumGreyCGColour: CGColor = #colorLiteral(red: 0.7540688515, green: 0.7540867925, blue: 0.7540771365, alpha: 1)
let bold17 = UIFont.boldSystemFont(ofSize: 17)
let hel17 = UIFont (name: "Helvetica", size: 17)
let hel20 = UIFont (name: "Helvetica", size: 20)
// Create button to present the UIAlert with textField workaround view
let yourButton = UIButton()
func createYourButton()
{
view.addSubview(yourButton)
yourButton.translatesAutoresizingMaskIntoConstraints = false
yourButton.backgroundColor = .red
yourButton.setTitle("TAP ME", for: .normal)
yourButton.addTarget(self, action: #selector(saveButtonTap), for: .touchUpInside)
NSLayoutConstraint.activate([
yourButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
yourButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
yourButton.widthAnchor.constraint(equalToConstant: 100),
yourButton.heightAnchor.constraint(equalToConstant: 50),
])
}
#objc func saveButtonTap()
{
saveName()
}
func saveName()
{
textfieldUIAlert()
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(200), execute:
{
self.textFieldView.isHidden = false
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300), execute:
{
self.textFieldField.becomeFirstResponder()
})
})
}
func textfieldUIAlert()
{
view.addSubview(textFieldView)
textFieldView.isHidden = true
textFieldView.translatesAutoresizingMaskIntoConstraints = false
textFieldView.backgroundColor = LightGreyUIColour
textFieldView.layer.cornerRadius = 16
textFieldView.addSubview(textFieldLabel)
textFieldLabel.translatesAutoresizingMaskIntoConstraints = false
textFieldLabel.textAlignment = .center
textFieldLabel.font = bold17
textFieldLabel.text = "NAME IT"
textFieldView.addSubview(textFieldField)
textFieldField.translatesAutoresizingMaskIntoConstraints = false
textFieldField.backgroundColor = WhiteUIColour
textFieldField.layer.borderColor = MediumGreyCGColour
textFieldField.layer.borderWidth = 0.5
textFieldField.layer .cornerRadius = 9
textFieldField.font = hel20
textFieldField.textAlignment = .center
textFieldView.addSubview(textFieldButton)
textFieldButton.translatesAutoresizingMaskIntoConstraints = false
textFieldButton.setTitleColor(DarkBlueUIColour, for: .normal)
textFieldButton.titleLabel?.font = hel17
textFieldButton.setTitle("SAVE", for: .normal)
textFieldButton.addTarget(self, action: #selector(textFieldButtonTap), for: .touchUpInside)
NSLayoutConstraint.activate([
textFieldView.topAnchor.constraint(equalTo: view.centerYAnchor, constant: -250),
textFieldView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
textFieldView.bottomAnchor.constraint(equalTo: view.centerYAnchor, constant: -90),
textFieldView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 7/10),
textFieldLabel.topAnchor.constraint(equalTo: textFieldView.topAnchor),
textFieldLabel.centerXAnchor.constraint(equalTo: textFieldView.centerXAnchor),
textFieldLabel.widthAnchor.constraint(equalTo: textFieldView.widthAnchor),
textFieldLabel.heightAnchor.constraint(equalToConstant: 50),
textFieldField.centerXAnchor.constraint(equalTo: textFieldView.centerXAnchor),
textFieldField.centerYAnchor.constraint(equalTo: textFieldView.centerYAnchor, constant: -10),
textFieldField.heightAnchor.constraint(equalToConstant: 33),
textFieldField.widthAnchor.constraint(equalTo: textFieldView.widthAnchor, multiplier: 8.5/10),
textFieldButton.topAnchor.constraint(equalTo: textFieldField.bottomAnchor, constant: 15),
textFieldButton.bottomAnchor.constraint(equalTo: textFieldView.bottomAnchor),
textFieldButton.centerXAnchor.constraint(equalTo: textFieldView.centerXAnchor),
textFieldButton.widthAnchor.constraint(equalTo: textFieldView.widthAnchor),
])
}
#objc func textFieldButtonTap()
{
if textFieldField.text!.count < 1 || textFieldField.text == " " || textFieldField.text == " " || textFieldField.text == " "
{
let TooShort = UIAlertController(title: "TOO SHORT", message: "\n\nTHE NAME\n\n YOU ARE SAVING\n\nIS TOO SHORT\n", preferredStyle: .alert)
TooShort.view.tintColor = #colorLiteral(red: 0.5818830132, green: 0.2156915367, blue: 1, alpha: 1)
TooShort.view.layer.cornerRadius = 15
TooShort.view.layer.borderWidth = 5
TooShort.view.layer.borderColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
func okHandler(alert: UIAlertAction!)
{
// Do something if you feel like it
}
self.present(TooShort, animated: true, completion: nil)
TooShort.addAction(UIAlertAction(title: "OK", style: .default, handler: okHandler))
}
else
{
//DON'T DO WHAT I DO, DO SOMETHING EQUALLLY AWESOME
doingSomethingAwesome()
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500), execute:
{
self.textFieldField.text = .none
self.textFieldView.isHidden = true
})
}
}
func doingSomethingAwesome()
{
let saved = UIAlertController(title: "SAVED", message: "\n\nYOU HAVE\n\nSAVED THE NAME\n\n", preferredStyle: .alert)
saved.view.tintColor = #colorLiteral(red: 0.01680417731, green: 0.1983509958, blue: 1, alpha: 1)
saved.view.layer.cornerRadius = 15
saved.view.layer.borderWidth = 5
saved.view.layer.borderColor = #colorLiteral(red: 0, green: 0.9768045545, blue: 0, alpha: 1)
func okHandler(alert: UIAlertAction!)
{
...
}
self.present(saved, animated: true, completion: nil)
saved.addAction(UIAlertAction(title: "OK", style: .default, handler: okHandler))
}
override func viewDidLoad() {
super.viewDidLoad()
createYourButton()
}
}
// Actually took me 30 mins to post this, so if I've missed something, let me know✌️
// Because I have a scrollView, I figured this was next best thing to disabling it while that view was showing
func scrollViewWillBeginDragging(_ scrollView: UIScrollView)
{
textFieldView.isHidden = true
}

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)
}

How to customise UISearchController?

I'm using a UISearchController in my application but I can't figure a way to customise it. I looked here in Stackoverflow but none of the confirmed answers worked for me. I tried looking in more places but nothing works.
This is my code:
import UIKit
class MainVC: UIViewController {
lazy var mSearchBarController: UISearchController = {
let mSearchBar = UISearchController(searchResultsController: nil)
mSearchBar.searchBar.barStyle = .default
mSearchBar.searchBar.placeholder = "enter city here"
mSearchBar.searchBar.tintColor = UIColor.white
return mSearchBar
}()
override func viewDidLayoutSubviews() {
setupSearchBar()
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(red: 80/255, green: 135/255, blue: 179/255, alpha: 1.0)
setupNavBar()
self.navigationItem.searchController = mSearchBarController
}
private func setupNavBar(){
navigationItem.title = "Home"
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.hidesSearchBarWhenScrolling = true
}
private func setupSearchBar(){
let mSearchTextField = mSearchBarController.searchBar.value(forKey: "searchField") as? UITextField
mSearchTextField?.textColor = UIColor(red: 255/255, green: 245/255, blue: 139/255, alpha: 1.0)
let mAttributedPlaceholder = NSMutableAttributedString(string: "enter city here", attributes: [NSAttributedString.Key.foregroundColor : UIColor(red: 255/255, green: 245/255, blue: 139/255, alpha: 1.0)])
mSearchTextField?.attributedPlaceholder = mAttributedPlaceholder
for view in mSearchBarController.searchBar.subviews {
for subview in view.subviews {
if let textField = subview as? UITextField {
textField.backgroundColor = UIColor.red
textField.textColor = UIColor.white
}
}
}
}
}
I can't figure a way to change the textColor of the searchBar nor the backgroundColor of it.
This is what I get:
See I use this simple code to change the textColor and backgroundColor of seacrhBar:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
for view in searchBar.subviews {
for subview in view.subviews {
if let textField = subview as? UITextField {
textField.backgroundColor = UIColor.red
textField.textColor = UIColor.white
}
}
}
}
for reference you can check:-
How can I change the UISearchBar search text color? (for textcolor)
http://jitu1990.blogspot.com/2017/06/textcolor-and-backgroundcolor.html (for backgorund color)

Allow Action When Tapping UITextView

I would like to be able to effectively use a UITextView as a button in my Swift iOS application. When I tap on the text view, I don't want it to be editable, but I want it to change the background color of the text view and begin using the speech recognition software in the app. I've seen some other questions similar to this, but none answering this specific question.
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
guard textView == inView else {
guard textView == resultView else {
return false
}
nextButton.isEnabled = true
return false
}
if audioEngine.isRunning {
let myColor: UIColor = UIColor(red: 50, green: 0, blue: 0, alpha: 0.75)
inView.layer.backgroundColor = myColor.cgColor
audioEngine.inputNode.removeTap(onBus: 0)
globalVariables.boolRecording = false
audioEngine.stop()
recognitionRequest?.endAudio()
microphoneButton.isEnabled = true
microphoneButton.setTitle("Start Recording", for: .normal)
globalVariables.finalText = globalVariables.finalText + globalVariables.tempText
globalVariables.tempText = ""
self.inView.text = ""
return false
} else {
let myColor: UIColor = UIColor(red: 0, green: 50, blue: 0, alpha: 0.75)
inView.layer.backgroundColor = myColor.cgColor
globalVariables.boolRecording = true
startRecording()
microphoneButton.setTitle("Stop Recording", for: .normal)
return false
}
}
You can use UITextViewDelegate method:textViewShouldBeginEditing.
Return false from this method to prevent making this particular textfield firstResponder and change the background and start your speech recognition.
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
guard textView == speechTextView else {
return true
}
// Change bg
speechTextView.backgroundColor = UIColor.blue
// Start speech
startSpeechRecognition()
return false
}
Don't forget to add delegate of UITextview to self:
speechTextView.delegate = self

UIButton does not change title

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)
}