I have a UISwitch, when it is toggled, the IBAction is triggered:
#IBAction func mySwitchToggled( switch_: UISwitch ) {
...
}
So, when user toggle the switch, the above function is invoked.
At some point, I also need to toggle the switch programmatically:
mySwitch.setOn(false, animated: false) //It triggers the IBAction function
The above code triggers the IBAction function.
For my special requirement, I need to have the IBAction function being triggered when user toggled the switch but when programmatically toggle the switch, I don't want the IBAction function get triggered.
How to programmatically toggle my switch without triggering the IBAction function?
hmmm... intersting. It gets triggered in my project
I don't have enough rep to comment so I post it as a answer going at PPL his answer, did you checked your outlets. Most of the time the storyboard keeps the connection to your other IB action which causing them to trigger both. (removing existing outlets and implementing the value change, should work)
Here is another (some what hacky) solution, by implementing a skip boolean when calling the switch by code:
var skip: Bool = false
#IBAction func mySwitchToggled( switch_: UISwitch ) {
guard !skip else {
skip = false
return
}
// do stuff
}
func someFunc() {
// called it like this
skip = true
mySwitch.setOn(false, animated: false)
}
Please find below, Here swcValueChanged is Value Changed function and it will call only when user toggle the switch.
#IBAction func swcValueChanged(_ sender: Any) {
print("Switch value changed")
}
Here on button tap event, above function will not call.
#IBAction func btnTapped(_ sender: Any) {
swcTemp.setOn(!swcTemp.isOn, animated: true)
}
Related
I have a UIButton that executes networking code upon clicking. The networking code updates a record on the server. Is there a way that I can prevent this networking code from being executed if the button is being repeatedly tapped, as this would just be a waste of resources?
In the IBAction, change the button's isUserInteractionEnabled property to false and set it back to true when the network request finishes execution.
You can add a flag in your class or use the request object to determine if the app is currently sending
Before starting the send change the value to true and after you finish set it back to false
in this way you can use the same button as a cancel button.
or you can show an alert about the sending state
here is a sample:
class ViewController: UIViewController {
var isSending = false
#IBAction func sendTouched(_ sender: UIButton) {
guard !isSending else { return }
send()
}
func send() {
isSending = true
// send data to server
}
// call this after you finish sending
func notifyFinished() {
isSending = false
}
}
i want to make 2 action for a button like that.
selected and deselected action for 1 button.
#IBAction func btntouch(sender: UIButton) {
if firsttouch
{
print bla bla
change button to selected style. maybe background color.
}
else
{
}
}
how can i do that?
In case you need to split two button statuses - like ON and OFF, try this:
var buttonSwitched : Bool = false
#IBAction func btntouch(sender: UIButton) {
//this line toggle your button status variable
//if true, it goes to false, and vice versa
self.buttonSwitched = !self.buttonSwitched
if self.buttonSwitched
{
//your UI styling
}
else
{
//your opposite UI styling
}
}
Create 2 IBActions:
#IBAction func touchDown(_ sender: AnyObject) {
print("down")
}
#IBAction func touchUp(_ sender: AnyObject) {
print("up")
}
When connecting the first one, make sure the event is set to touchDown. For the second one, make sure it is set to touchUpInside
Yes, you can. Depending on your requirements, you could store the current state of the button in the view controller or in the model.
If the visual change caused by the first touch needs to be persisted across opening and closing of your view controller, store the value indicating the change in the model; if you need to reset the visuals when the view controller shows, store the value in the view controller itself:
var firstTouch = true
#IBAction func btntouch(sender: UIButton) {
if firstTouch {
firstTouch = false
...
} else {
...
}
}
I've set up a function for editing did end with a slider, but it doesn't look like it's being called. I've thrown a print statement into it, and a breakpoint. Is there something else that needs to be done to trigger a function when my user lets go of the slider?
#IBAction func sliderEditingDidEnd(sender: UISlider) {
print("did end");
}
Use the event "Value Changed". If you just want updates for the final value, alter UISlider.continuous
var slider = UISlider()
slider.continuous = false
//add slider to view
#IBAction func valueChanged(sender: UISlider) {
println("Value changed.")
}
//prints "Value changed." once upon releasing slider.
If the slider needs to be continuous, you can implement an event for UIControlEvent.TouchUpInside.
Or in code:
override func viewDidLoad() {
super.viewDidLoad()
mySlider.addTarget(self, action: "userReleasedSlider:", forControlEvents: UIControlEvents.TouchUpInside)
// Do any additional setup after loading the view, typically from a nib.
}
func userReleasedSlider(slider: UISlider) {
print("User released slider.")
}
I think what you are trying to do is to get the notification when the value is changed. Then you have to set event to 'Value Changed' not 'Editing Did End'.
If you set both Touch Up Inside and Touch Up Outside to point to your #IBAction then you can get the function to fire when the user finishes sliding and keep the slider as continuous.
I have three buttons,and only one button can be chosen by the user at a time,that means that other then the initial state where none are chosen only one button can be at a highlighted state at a time.After another button (a forth one) is clicked,all the previous button's abilities to be clicked on are disabled.How do I do this?
button.enabled = false /// this will make a button disabled in swift
Why not use the 4th button to toggle a bool - that can be used to check on the state of the other buttons?
var lockedButtons: Bool = true
#IBAction func toggleButtonLock(sender: UIButton) {
lockedButtons = !lockedButtons
}
#IBAction func Button1(sender: UIButton) {
if !lockedButtons{
//Button1 code
}
}
//button 2 & 3 code similar....
I'm a noob here and in iOS world. I am having trouble dismiss keyboard on a specific case in my very simple todo list iOS app.
I'd like the keyboard to get dismiss when user taps anywhere outside the current text field or the keyboard itself. So far, I got the keyboard dismisses just fine (thanks to you guys here in stack overflow) when user taps on the UITableView, or most element on my app. HOWEVER, when user taps on another UITextField, the keyboard does not go away.
FYI, here's the list of existing threads I researched so far but have yet to solve this issue.
1) How to dismiss keyboard iOS programmatically
2) Resigning First Responder for multiple UITextFields
3) Dismissing the First Responder/Keyboard with multiple Textfields
4) (a few more at least but I lost track :( )
Here's what I did so far:
(in viewDidLoad())
// Add 'tap' gesture to dismiss keyboard when done adding/editing to-do item
var tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "tapOutside:")
tap.cancelsTouchesInView = true
self.view.addGestureRecognizer(tap)
func tapOutside(tapOutside: UIGestureRecognizer) {
// Dismiss keyboard
self.view.endEditing(true)
}
#IBAction func EditingDidBegin(sender: UITextField) {
// Highlight the text field which user is editing
self.highlightTextField(sender, highlight: true)
}
#IBAction func EditingDidEnd(sender: UITextField) {
// Undo text field highlight
self.highlightTextField(sender, highlight: false)
self.view.endEditing(true) // try this option and not working
self.setEditing(false, animated: true) // try this option and not working
sender.resignFirstResponder() // try this option and not working
UIApplication.sharedApplication().becomeFirstResponder() // try this option and not working
... // below is my code to update the todo item
}
I also tried to print out all subviews.isFirstResponder() of my view. All of it return false. I also tried override touchesBegan of my UIViewController, and inside it just calls self.view.endEditing(true) and call its super's. This also does not work.
Please help. :(
TIA!
UPDATE:
You guys are awesome! :D I got it working now thanks to you guys. There were several mistakes / messed up as I'm learning new framework. So here's what I did.
1) I did not set UITextField delegate correctly.
Mistake: I ctrl-draged textfield in xcode and link my viewController as delegate and thought that should work out. I will still need to research and understand better why.
Solution: I removed that ctrl-drag link and explicitly call myTextField.delegate = self in tableView:cellForRowAtIndexPath. And that did it. Thanks #Sidewalker
2) Mistake: I have a mixed of textFieldShouldBeginEditing, etc. and #IBAction func EditingDidBegin. So I got myself into the situation where textFieldShouldBeginEditing got the call, but EditingDidBegin did not get call.
Solution: Once I set the delegate = self explicitly and stick with implementing textField... methods and not use any #IBAction for textField, things just work.
Here's one option... We're going to add a boolean flag to determine whether or not we're in a textField when an edit attempt for another textField begins
Make your class adhere to UITextFieldDelegate
class MyClass: UIViewController, UITextFieldDelegate
Don't forget to set the delegate, we'll add the flag as well
myTextField.delegate = self
var inField = false
Implement "textFieldShouldBeginEditing" and "textFieldDidBeginEditing"
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
if inField {
inField = false
return false
}
return true
}
func textFieldDidBeginEditing(textField: UITextField) {
inField = true
}
I prefer tracking things like this rather than identifying subviews as it allows the flag to be utilized elsewhere and cuts down code complexity.
Well the keyboard isn't going away because it doesn't expect to have to. The new UITextField is just becoming the first responder while the other resigns. If you don't want a textField to become the first responder if another is already, you're going to have to cut it off before it gets the chance to. I would try to implement textFieldShouldBeginEditing and figuring out the logic there.
I'm not in love with the way this looks but this should do something along those lines.
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
for subView in self.view.subviews{
if(subView.isKindOfClass(UITextField)){
if(subView.isFirstResponder()){
subView.resignFirstResponder();
return false;
}
}
}
return true;
}
First set all the UITextField (your are creating) delegate as self and create one UITextField member variable. Now implement "textFieldDidBeginEditing" delegate method and assign the textfield to your member UITextField variable. As given below
func textFieldDidBeginEditing(textField: UITextField) {
yourMemberVariable = textField;
}
So now whenever you want to dismiss the keyboard call the dismiss method on "yourMemberVariable" object. It should work !!
What I usually do is implementing this two method:
The first one add a UITapGestureRecognizer to the whole UIViewController view
func hideKeyboard() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
view.addGestureRecognizer(tap)
}
The second one just get called every time the user touch anywhere on the UIViewController's view
func dismissKeyboard() {
self.view.resignFirstResponder()
}
I add the first one to the viewDidLoad method of the UIViewController. Or better yet if you want to use that on all the app just make that an extension for your UIViewController.
How about doing this in viewController, It works for me
func dismissKeyboard() {
//All the textFields in the form
let textFields = [textField1, textField2, textField3, textField4, textField5]
let firstResponder = textFields.first(where: {$0.isFirstResponder ?? false })
firstResponder?.resignFirstResponder()
}