Why is the Button enable not working when TextView has contents? - swift

Likely a very simple rookie mistake going on here but I'm trying to make sure a button is disabled until a TextView has text in it.
I set
Button.isEnabled = false
and then added this code. I've tried variations of this code in various ways, I'm seemingly unable to attach it to the textView itself, I can't imagine why this wouldn't be working.
#IBAction func valueChanged(_ sender: AnyObject)
{
if(title.text != "")
{
Button.isEnabled = true
}
else
{
Button.isEnabled = false
}
}
Thanks StackedOverflow Community ...

set button's enabled with alpha to make the look better then set enabled/disabled through valueChanged
#IBOulet private weak var myButton: UIButton! {
didSet {
set(myButton, enabled: false)
}
}
#IBAction private func valueChanged(_ sender: UITextView) {
set(myButton, enabled: !sender.text.isEmpty)
}
private func set(_ button: UIButton, enabled: Bool) {
button.isEnabled = enabled
button.alpha = enabled ? 1 : 0.5
}

Related

Switch control to toggle isHidden

I have an app with two switch controls to hide or show some textfield depending on their state on or off.
The problem is the first switch seems to control the second one.
If the first switch is off, the second switch is off also. I would like them to work independently from each other.
Any advice?
Thanks guys
#IBAction func switchP(_ sender: UISwitch) {
if (sender.isOn == true) {
textFieldP.isHidden = false
} else {
textFieldP.isHidden = true
}
}
#IBAction func switchT(_ sender: UISwitch) {
if (sender.isOn == true) {
textFieldT.isHidden = false
} else {
textFieldT.isHidden = true
}
}
First, replace
if (sender.isOn == true) {
textFieldP.isHidden = false
} else {
textFieldP.isHidden = true
}
by a simple single line:
textFieldP.isHidden = !sender.isOn
Second, use Connections Inspector (right panel, the arrow in the circle) and make sure your Referencing Outlets are not mixed or duplicated under the same IBAction.
Other than specifying the .isHidden = true using if/else statements, you should use an opposite property reference which is a lot nicer way of doing it.
#IBAction var switchP: [UIView] {
didSet {
textFieldP.forEach {
$0.isHidden = true
}
}
}
And to change based on a click:
#IBAction func switchP(_ sender: UISwitch) {
UIView.animate(withDuration: 0.2) {
self.switchP.forEach {
$0.isHidden = !$0.isHidden
}
}
}
That's the best I can generically answer without seeing all of your code.

Search cursor disappearing when cancel button hidden

I followed the great directions in this post to subclass a search bar and search controller that does not show the cancel button. However, there is now no cursor in my search bar when I start editing. I've tried setting the tint for the search bar, which I've seen as an answer in many posts, in various delegate methods. The tint is technically being set correctly, as I can see when I test it by setting my search controller to be the standard UISearchController. But as soon as I set it to my subclass SearchControllerWithoutCancel the cursor goes away.
Here are my subclasses:
class SearchBarWithoutCancel: UISearchBar {
override func layoutSubviews() {
super.layoutSubviews()
setShowsCancelButton(false, animated: false)
}
}
class SearchControllerWithoutCancel: UISearchController, UISearchBarDelegate {
lazy var _searchBar: SearchBarWithoutCancel = {
[unowned self] in
let result = SearchBarWithoutCancel(frame: .zero)
result.delegate = self
return result
}()
override var searchBar: UISearchBar {
get {
return _searchBar
}
}
}
And here's my addSearchController method which I call from viewDidLoad()
func addSearchController() {
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.autocapitalizationType = .none
searchController.searchBar.searchBarStyle = .minimal
searchController.searchBar.tintColor = UIColor.black
self.definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
}
Has anyone encountered this before? Thanks :)
indeed when the cancel button is hidden, the cursor tint color resets itself
in your SearchBarWithoutCancel remove the layoutSubviews and override setShowsCancelButton :
override func setShowsCancelButton(_ showsCancelButton: Bool, animated: Bool) {
//nothing
}}
objective-c version
-(void) setShowsCancelButton:(BOOL)show animated:(BOOL)animated
{
//nothing
}

Fade out NSButton using NSAnimationContext

I have a simple Swift macOS app (using Xcode 8.2.1) that contains a single NSButton. When I click the button I would like it to fade out over a specified period. I thought I could use NSAnimationContext but no matter what value I set the context duration the button fades out almost immediately. Is this not the right way to do this?
class ViewController: NSViewController {
#IBOutlet weak var basicButton: NSButton!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func basicButtonClicked(_ sender: NSButton) {
NSAnimationContext.runAnimationGroup({ (context) in
context.duration = 10.0
self.basicButton.animator().alphaValue = 1
}) {
self.basicButton.animator().alphaValue = 0
}
}
}
I misunderstood how the animator values worked during the animation. The right way to set this up is:
#IBAction func basicButtonClicked(_ sender: NSButton) {
NSAnimationContext.runAnimationGroup({ (context) in
context.duration = 10.0
// Use the value you want to animate to (NOT the starting value)
self.basicButton.animator().alphaValue = 0
})
}

Implement checkbox in Swift

I am trying to implement a checkbox in Swift. I used the answer of an other post to get started.
First I created a button in the storyboard and gave it the class checkbox. After that I, created the class checkbox. It is currently looking like that. I had do make some adjustments from the other post, because he was using a different version of swift.
class checkbox: UIButton {
//Images
let checkedImage = UIImage(named: "selected")! as UIImage
let uncheckedImage = UIImage(named: "rectangle")! as UIImage
// Bool property
var isChecked: Bool = false {
didSet{
if isChecked == true {
self.setImage(checkedImage, for: .normal)
} else {
self.setImage(uncheckedImage, for: .normal)
}
}
}
func buttonClicked(sender: UIButton) {
if (sender == self) {
if self.isChecked == true
{
self.isChecked = false
}
else
{
self.isChecked = true
}
}
}
override func awakeFromNib() {
self.addTarget(self, action: Selector(("buttonClicked:")),for:UIControlEvents.touchUpInside)
self.isChecked = false
}
}
But now, I always get the following error in the AppDelegate, when I click the checkbox.
terminating with uncaught exception of type NSException
try this -
class CheckBoxButton: UIButton {
override func awakeFromNib() {
self.setImage(UIImage(named:"selected"), for: .selected)
self.setImage(UIImage(named:"rectangle"), for: .normal)
self.addTarget(self, action: #selector(CheckBoxButton.buttonClicked(_:)), for: .touchUpInside)
}
func buttonClicked(_ sender: UIButton) {
self.isSelected = !self.isSelected
}
}
I also recently had to make a checkbox and I used a cocoapod for that, instead of making my own. It lets you choose everything including colors, animations, shape and size! Maybe that helps:
BEM CHECKBOX
It really only takes 5 min to install and have it working on your app.
Safest way to make check box:
Add a UIButton to ViewController
Add two images to Project: 1.checked.png, 2.un-checked.png
Set checked or un-checked image as button background or button image
Set button text to ""
believe me, that libraries will make you confused.

Swift - validating UITextField

I have these outlets in my app:
#IBOutlet var name1: UITextField!
#IBOutlet var name2: UITextField!
#IBOutlet var name3: UITextField!
#IBOutlet var name4: UITextField!
#IBOutlet var newButton: UIButton!
What I tried to do is the following:
Every time the user types something in one of these four UITextFields or deletes something, I want to check if any UITextField is empty
If any UITextField is empty, the button should be disabled.
If all UITextFields are set (not empty), the button should be enabled.
My code:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
setButton()
return true
}
func setButton() {
let inputValid = checkInput()
if inputValid {
newButton.enabled = true
} else {
newButton.enabled = false
}
}
func checkInput() -> Bool {
let name1Value = name1.text
let name2Value = name2.text
let name3Value = name3.text
let name4Value = name4.text
if !name1Value.isEmpty && !name2Value.isEmpty && !name3Value.isEmpty && !name4Value.isEmpty {
return true
}
return false
}
Ok, it works 50% for now.
When I type one character in each UITextField, the button is still disabled.
When I add a second one to any UITextField, the button gets enabled etc...
Can anyone help me with this?
Alternatively, you can use this, which is called every time a key is pressed:
name1.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
name2.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
name3.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
name4.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
func textFieldDidChange(textField: UITextField) {
if name1.text?.isEmpty || name2.text?.isEmpty || name3.text?.isEmpty || name4.text?.isEmpty {
//Disable button
} else {
//Enable button
}
}
Swift 4
- Here is how I have solved it trying to avoid long conditionals
- This will also allow you to do realtime validation on each individual textfield, unlike the accepted answer, you can update your UI according to what the user is typing.
let textfields : [UITextField] = [name1, name2, name3, name4]
for textfield in textfields {
textfield.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
}
#objc func textFieldDidChange(_ textField: UITextField) {
//set Button to false whenever they begin editing
yourButton.isEnabled = false
guard let first = textFields[0].text, first != "" else {
print("textField 1 is empty")
return
}
guard let second = textFields[1].text, second != "" else {
print("textField 2 is empty")
return
}
guard let third = textFields[2].text, third != "" else {
print("textField 3 is empty")
return
}
guard let forth = textFields[3].text, forth != "" else {
print("textField 4 is empty")
return
}
// set button to true whenever all textfield criteria is met.
yourButton.isEnabled = true
}
The textField:shouldChangeCharactersInRange: method gets called BEFORE the contents of the text field have changed.
You should special-case the current text field and figure out if it's new contents are going to be blank after the edit.
Something like this:
textField.text.length > range.length - replacementString.length
(That's off the top of my head, and not debugged. Plus you would have to come up with logic that makes sure all the other fields are non-blank, and use the logic above to test the contents of the current field.)
Take a look at UITextFieldValidator. I have created a validator which covers almost each validation required in an app. Also its in swift. So go ahead and check it out.
Try this code. Hope you will get what to do.
func updateSaveButtonState() {
let text = titleTextField.text ?? ""
saveButton.isEnabled = !text.isEmpty
}
#IBAction func textEditingChanged(_ sender: UITextField) {
updateSaveButtonState()
}
#IBAction func returnPressed(_ sender: UITextField) {
titleTextField.resignFirstResponder()
}
Swift 4 & 5
Firstly, you create a function like setupTextFields() and you call it in viewDidLoad() (something like this):
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setupTextFields() //You call the function here.
}
func setupTextFields() {
name1.addTarget(self, action: #selector(self.textFieldDidChange(_:)), for: UIControl.Event.editingChanged)
name2.addTarget(self, action: #selector(self.textFieldDidChange(_:)), for: UIControl.Event.editingChanged)
name3.addTarget(self, action: #selector(self.textFieldDidChange(_:)), for: UIControl.Event.editingChanged)
name4.addTarget(self, action: #selector(self.textFieldDidChange(_:)), for: UIControl.Event.editingChanged)
}
Then you create another function which each time you press a key, that function will be called. I'll show you two options, then you choose which fits better for you. Usually, Option 1 would be considered a better implementation for Swift.
Option 1
#objc func textFieldDidChange(_ textField: UITextField) {
guard !name1.text!.isEmpty else {
button.isEnabled = false
return
}
guard !name2.text!.isEmpty else {
button.isEnabled = false
return
}
guard !name3.text!.isEmpty else {
button.isEnabled = false
return
}
guard !name4.text!.isEmpty else {
button.isEnabled = false
return
}
button.isEnabled = true
}
Option 2
#objc func textFieldDidChange(_ textField: UITextField) {
if name1.text!.isEmpty || name2.text!.isEmpty || name3.text!.isEmpty || name4.text!.isEmpty {
button.isEnabled = false
} else {
button.isEnabled = true
}
}