I have searched various sources and could not find a clear and simple solution for creating the equivalent of a radio button group in Swift 3 with Xcode 8.3 for an iOS application.
For example if I have 3 buttons in one group and only one should be selected at a time. Currently I am implementing this by changing the state of 2 buttons in the group to not selected when the other one is selected and vice versa.
#IBAction func buttonA(_ sender: Any) {
buttonB.isChecked = false
buttonC.isChecked = false
}
#IBAction func buttonB(_ sender: Any) {
buttonA.isChecked = false
buttonC.isChecked = false
}
#IBAction func buttonC(_ sender: Any) {
buttonA.isChecked = false
buttonB.isChecked = false
}
However I would expect a more efficient way to do this.
Any help on a more efficient solution will be appreciated.
You can connect all your button's IBAction to one single method.
#IBAction func buttonClick(_ sender: UISwitch) { // you're using UISwitch I believe?
}
You should add all the buttons into an array:
// at class level
var buttons: [UISwitch]!
// in viewDidLoad
buttons = [buttonA, buttonB, buttonC]
Then, write the buttonClick method like this:
buttons.forEach { $0.isChecked = false } // uncheck everything
sender.isChecked = true // check the button that is clicked on
Alternatives:
Try using a UITableView. Each row contains one option. When a row is selected, change that row's accessoryType to .checkMark and every other row's to .none.
If you are too lazy, try searching on cocoapods.org and see what other people have made.
Just make a single selector for all three button's touchUpInside event, and set radio_off image for normal state and radio_on image for selected state in your IB, then only you have to connect btnClicked method to all button's touchUpInside event
class ViewController: UIViewController {
#IBOutlet weak var btnFirst:UIButton!
#IBOutlet weak var btnSecond:UIButton!
#IBOutlet weak var btnThird:UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func btnClicked(sender:UIButton){
let buttonArray = [btnFirst,btnSecond,btnThird]
buttonArray.forEach{
$0?.isSelected = false
}
sender.isSelected = true
}
Depending on your UI, you could take multiple approaches.
UITableView - Use a UITableView with a checkmark decorator. If your layout for these radio buttons is fairly traditional, this is the correct paradigm. If the layout is a grid instead of a list, you could use UICollectionView.
You can use the func table(_ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) in UITableViewDelegate to capture the selection. You can call indexPathForSelectedRow on the tableView when you want to commit the change to determine which cell was selected.
Apple's tutorial on UITableView can be found at:
https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/CreateATableView.html
Manage a group of UIButtons - You could store an array of references to UIButton objects that are part of your radio button group.
protocol RadioButtonDelegate: class {
func didTapButton(_ button: UIButton)
}
class RadioButtonGroup {
private var buttons: [UIButton] = []
weak var delegate: RadioButtonDelegate?
var selectedButton: UIButton? { return buttons.filter { $0.isSelected }.first }
func addButton(_ button: UIButton) {
buttons.append(button)
}
#objc private func didTapButton(_ button: UIButton) {
button.isSelected = true
deselectButtonsOtherThan(button)
delegate?.didTapButton(button)
}
private func deselectButtonsOtherThan(_ selectedButton: UIButton) {
for button in buttons where button != selectedButton {
button.isSelected = false
}
}
}
class MyView: UIView {
private var radioButtonGroup = RadioButtonGroup()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let button1 = UIButton(type: .custom)
button1.setTitle("Eeeny", for: .normal)
let button2 = UIButton(type: .custom)
button2.setTitle("Meeny", for: .normal)
let button3 = UIButton(type: .custom)
button3.setTitle("Miny", for: .normal)
self.radioButtonGroup.addButton(button1)
self.radioButtonGroup.addButton(button2)
self.radioButtonGroup.addButton(button3)
addSubview(button1)
addSubview(button2)
addSubview(button3)
}
}
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var maleLB: UIButton!
#IBOutlet weak var femaleLB: UIButton!
#IBOutlet weak var otherLB: UIButton!
var gender = "Male"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if gender == "Male"{
femaleLB.isSelected = true
}
}
#IBAction func maleBtn(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
femaleLB.isSelected = false
otherLB.isSelected = false
}
else{
sender.isSelected = true
femaleLB.isSelected = false
otherLB.isSelected = false
}
}
#IBAction func femaleBtn(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
maleLB.isSelected = false
otherLB.isSelected = false
}
else{
sender.isSelected = true
maleLB.isSelected = false
otherLB.isSelected = false
}
}
#IBAction func otherBtn(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
maleLB.isSelected = false
femaleLB.isSelected = false
}
else{
sender.isSelected = true
maleLB.isSelected = false
femaleLB.isSelected = false
}
}
}
Related
I'm creating a simple log in VC. let's ignore the input validation for both username & password. I just want to enable the UIButton when both username's and password's UITextField is not empty. And whenever any one of them becomes empty, I want the button to be disabled.
#IBAction func typingUserName(_ sender: Any) {
usernameTxtfield.layer.shadowPath = UIBezierPath(rect: usernameTxtfield.bounds).cgPath
usernameTxtfield.layer.shadowRadius = 2
usernameTxtfield.layer.shadowOffset = .zero
usernameTxtfield.layer.shadowOpacity = 0.5
signInIcon.isEnabled = false
}
#IBAction func typingPassword(_ sender: Any) {
passwordTxtfield.layer.shadowPath = UIBezierPath(rect: passwordTxtfield.bounds).cgPath
passwordTxtfield.layer.shadowRadius = 2
passwordTxtfield.layer.shadowOffset = .zero
passwordTxtfield.layer.shadowOpacity = 0.5
signInIcon.isEnabled = false
}
#IBAction func usernameTxtFieldEditingChnged(_ sender: Any) {
usernameTxtfield.layer.shadowRadius = 0
usernameTxtfield.layer.shadowOffset = .zero
usernameTxtfield.layer.shadowOpacity = 0
}
#IBAction func passwordEditingChaned(_ sender: Any) {
passwordTxtfield.layer.shadowRadius = 0
passwordTxtfield.layer.shadowOffset = .zero
passwordTxtfield.layer.shadowOpacity = 0
signInIcon.isEnabled = true
}
#IBAction func signInClicked(_ sender: Any) {
performSegue(withIdentifier: "welcomeVC", sender: signInIcon)
}
As you can see, I'm enabling the button only after the password textfield EditingChanged has been triggered.
You can observe event .editingChanged.
passwordTxtfield.addTarget(self, action: #selector(passwordEditingChaned), for: .editingChanged)
usernameTxtfield.addTarget(self, action: #selector(usernameTxtFieldEditingChnged), for: .editingChanged)
And then add check in both methods:
signInIcon.isEnabled = passwordTxtfield.text?.isEmpty == false && usernameTxtfield.text?.isEmpty == false
You have to implement something like this:
if usernameTxtfield.text != "" && passwordTxtfield.text != "" {
signInIcon.isEnabled = true
} else {
signInIcon.isEnabled = false
}
You add this piece of code in the action of each UITextField and your are good to go
Connect outlets of textFields and Button to ViewController Class.
#IBOutlet private weak var usernameTxtfield: UITextField!
#IBOutlet private weak var passwordTxtfield: UITextField!
#IBOutlet private weak var signInButton: UIButton!
then write your setup function
private func setupTextFields() {
// write your TextFields custom setup ...
// also add delegate lines
usernameTxtfield.delegate = self
passwordTxtfield.delegate = self
}
your setupTextFields function to viewDidLoad of VC and also set your button isEnable = false
override func viewDidLoad() {
super.viewDidLoad()
setupTextFileds()
setSignInButton(isEnable: false)
}
and also write func to get textFields.
private func getTextFields() -> [UITextField] {
return [usernameTxtfield, passwordTxtfield]
}
also we need to check if these are valid.
private func isInputsValid() -> Bool {
var isValid: Bool = true
let inputs: [UITextField] = getTextFields()
if let input = inputs.first(where: { $0.text?.count == 0 }) {
debugPrint("\(input) is not valid.")
isValid = false
}
return isValid
}
also add func to set Button
private func setSignInButton(isEnable: Bool) {
signInButton.isEnabled = isEnable
}
then write TextField delegate func to understand inputs are changing and change condition of button.
extension ViewController: UITextFieldDelegate {
func textFieldDidChangeSelection(_ textField: UITextField) {
setSignInButton(isEnable: isInputsValid())
}
}
I hope it was helpful :)
I'm creating a test that has 5 buttons, each button corresponds to a specific color, the problem is that when I select a consecutive 2nd button, the previous button is still selected, how can I make my code select only one button at a time and deselect the previous one?
How can I fix this?
This is my code
class ViewController: UIViewController {
var buttonPressed: Bool = false
#IBOutlet weak var button1: UIButton!
#IBAction func buttonAction1(_ sender: UIButton) {
if buttonPressed {
buttonPressed = false
button1.setImage(UIImage(named: "Bolinha-5"), for: .normal)
}
else {
buttonPressed = true
button1.setImage(UIImage(named: "Bolinha-4"), for: .normal)
}
}
#IBOutlet weak var button2: UIButton!
#IBAction func buttonAction2(_ sender: UIButton) {
if buttonPressed {
buttonPressed = false
button2.setImage(UIImage(named: "Bolinha-5"), for: .normal)
}
else {
buttonPressed = true
button2.setImage(UIImage(named: "Bolinha-4"), for: .normal)
}
}
#IBOutlet weak var button3: UIButton!
#IBAction func buttonAction3(_ sender: UIButton) {
if buttonPressed {
buttonPressed = false
button3.setImage(UIImage(named: "Bolinha-2"), for: .normal)
}
else {
buttonPressed = true
button3.setImage(UIImage(named: "Bolinha-4"), for: .normal)
}
}
#IBOutlet weak var button4: UIButton!
#IBAction func buttonAction4(_ sender: UIButton) {
if buttonPressed {
buttonPressed = false
button4.setImage(UIImage(named: "Bolinha-3"), for: .normal)
}
else {
buttonPressed = true
button4.setImage(UIImage(named: "Bolinha-4"), for: .normal)
}
}
#IBOutlet weak var button5: UIButton!
#IBAction func buttonAction5(_ sender: UIButton) {
if buttonPressed {
buttonPressed = false
button5.setImage(UIImage(named: "Bolinha-3"), for: .normal)
}
else {
buttonPressed = true
button5.setImage(UIImage(named: "Bolinha-4"), for: .normal)
}
}
}
What you are going to accomplish is called Radio Buttons, unfortunately iOS (unlike macOS) doesn't provide this functionality.
My suggestion takes advantage of the option to assign different images to different states in Interface Builder – in this case the Default and Selected state – and to create an outlet collection, an array representing a sequence of UI elements of the same type.
The suggestion doesn't support an empty selection, by default the first button is selected.
In ViewController
create an outlet collection
#IBOutlet var buttons : [UIButton]!
and one IBAction
#IBAction func buttonAction(_ sender: UIButton) { }
In Interface Buider
set the images to the Default and Selected states of each button in the Attribute Inspector.
connect the buttons in the proper order to the outlet collection.
assign the tags 0 to 4 to the buttons in the same order.
connect all buttons also to the (same) IBAction.
In ViewController
create a property for the tag of the currently selected button
var selectedButton = 0
in viewDidLoad select the first button
override func viewDidLoad() {
super.viewDidLoad()
buttons[selectedButton].isSelected = true
}
Complete the IBAction, it deselects the previous button and selects the current.
#IBAction func buttonAction(_ sender: UIButton) {
let tag = sender.tag
buttons[selectedButton].isSelected = false
buttons[tag].isSelected = true
selectedButton = tag
}
let's consider you have named your buttons as follows: 1st button: "opt1Button", 2nd button: "opt2Button", 3rd button: "opt3Button" and so on...
create an IBAction with name "optionSelected" The function will look like:
#IBAction func optionSelected(_ sender: UIButton) {
opt1Button.isSelected = false
opt2Button.isSelected = false
opt3Button.isSelected = false
opt4Button.isSelected = false
opt5Button.isSelected = false
sender.isSelected = true
}
As soon any of the options is selected all the buttons will go to 'isSelected' false condition i.e all the buttons will be deselected at first and the selected button will be marked as selected. Same process will be followed again when any of the button is selected, everything will get deselected and the button user has pressed will be marked as selected.
Found this answer from (https://developer.apple.com/forums/thread/685124) and it worked for me.
I have multiple checkboxes that work decently.
The way it works is that there's two images (an image of a checked box OR an image of an unchecked box) that show up or disappear into my button, based on clicking that button.
For some reason when it's the first time I click a checkbox it works perfectly (changes its state to: checked or unchecked - when clicked once), but when i go to try a second, third, or fourth (etc.) checkbox, it requires two clicks to change its state (checked/unchecked).
This is annoying and confusing to the user. Is there any way around this?
Here are my last 3 checkboxes:
/////Checkboxes
#IBOutlet weak var Box49: UIButton!
#IBOutlet weak var Box50: UIButton!
#IBOutlet weak var Box51: UIButton!
var BoxON = UIImage(named: "CheckBox")
var BoxOFF = UIImage(named:"UnCheckBox")
var isBoxClicked: Bool!
override func viewDidLoad() {
super.viewDidLoad()
isBoxClicked = false
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func Box49(_ sender: Any) {
if isBoxClicked == true{
isBoxClicked = false
}else{
isBoxClicked = true
}
if isBoxClicked == true{
Box49.setImage(BoxON, for: UIControlState.normal)
}else{
Box49.setImage(BoxOFF, for: UIControlState.normal)
}
}
#IBAction func Box50(_ sender: Any) {
if isBoxClicked == true{
isBoxClicked = false
}else{
isBoxClicked = true
}
if isBoxClicked == true{
Box50.setImage(BoxON, for: UIControlState.normal)
}else{
Box50.setImage(BoxOFF, for: UIControlState.normal)
}
}
#IBAction func Box51(_ sender: Any) {
if isBoxClicked == true{
isBoxClicked = false
}else{
isBoxClicked = true
}
if isBoxClicked == true{
Box51.setImage(BoxON, for: UIControlState.normal)
}else{
Box51.setImage(BoxOFF, for: UIControlState.normal)
}
}
Thanks, Dan
The issue you are using same instance property isBoxClicked with all button instead of that you need to set the image to all button for both state normal and selected and then in your button action simply changed its selected state.
Also either change your button outlet name or action name because they both are same. So it should be like this.
#IBOutlet var box49: UIButton!
#IBOutlet var box50: UIButton!
#IBOutlet var box51: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
box49.setImage(BoxOFF, for: .normal)
box49.setImage(BoxON, for: .selected)
box50.setImage(BoxOFF, for: .normal)
box50.setImage(BoxON, for: .selected)
box51.setImage(BoxOFF, for: .normal)
box51.setImage(BoxON, for: .selected)
}
And now set your button action this way.
#IBAction func box49Button(_ sender: Button) {
sender.isSelected = !sender.isSelected
}
#IBAction func box50Button(_ sender: Button) {
sender.isSelected = !sender.isSelected
}
#IBAction func box51Button(_ sender: Button) {
sender.isSelected = !sender.isSelected
}
Or you can add single button action and set that action to all three button instead of having three different action for each button like this.
#IBAction func boxButton(_ sender: Button) {
sender.isSelected = !sender.isSelected
}
you are using one instance of isBoxClicked variable for all button. You should create an array of isBoxClicked. by using array you can check further that which checkbox(UIButon) is check an which is unchecked .
var isBoxClickedArray:[int] = {0,0}
First create enum for get index of buttons
enum ButtonIndex{
case Box49
case Box50
}
assign enum value as tag in button
Box49Button.tag = ButtonIndex.Box49.rawValue
Box50Button.tag = ButtonIndex.Box50.rawValue
create one method for get action
#IBAction func actionType(_ sender: Any) {
let button = sender as! UIBarButton
if ( button.tag == ButtonIndex.BOX49.rawValue ){
print("Box49 button pressed")
if ( isBoxClicked[ButtonIndex.BOX49.rawValue] == 0 ){
print("box49 is unchecked")
isBoxClicked[ButtonIndex.BOX49.rawValue] = 1// change it's value to checked
// change image also
}else{
// box is checked
isBoxClicked[ButtonIndex.BOX49.rawValue] = 0
// change value in array and image also
}
}else{
print("Box50 button pressed")
}
}
update
declare array in viewcontroller. and assign tag on button in viewdidload or cellforrowAtindexpath if you are using tableview. for enum declare them like this
import UIKit
enum indexs : Int{
case first
case second
}
class ViewController: UIViewController {
I have two modified buttons to be a checkbox with a subclass, the checkbox is siCheckbox and noCheckbox. if siCheckbox is checked the other will be unchecked.
The problem is , if i press siCheckBox again will set noCheckbox checked and siCheckBox unchecked
this is my code
import UIKit
class Paso1: UIViewController, CheckBoxDelegate {
#IBOutlet weak var siCheckBox: CheckBox!
#IBOutlet weak var noCheckBox: CheckBox!
override func viewDidLoad() {
super.viewDidLoad()
self.siCheckBox.delegate = self
self.noCheckBox.delegate = self
}
func checkBoxDidChange(checkbox: CheckBox) {
if checkbox == self.siCheckBox {
self.noCheckBox.isChecked = !checkbox.isChecked
} else {
self.siCheckBox.isChecked = !checkbox.isChecked
}
}
and this is the subclass for the buttons checkbox
protocol CheckBoxDelegate {
func checkBoxDidChange(checkbox: CheckBox) -> Void
}
import UIKit
class CheckBox: UIButton {
// Images
let checkedImage = UIImage(named: "check-greenb")! as UIImage
let uncheckedImage = UIImage(named: "check-baseb")! as UIImage
var delegate: CheckBoxDelegate?
// Bool property
var isChecked: Bool = false {
didSet{
if isChecked == true {
self.setImage(checkedImage, forState: .Normal)
} else {
self.setImage(uncheckedImage, forState: .Normal)
}
}
}
override func awakeFromNib() {
self.addTarget(self, action: #selector(CheckBox.buttonClicked(_:)), forControlEvents: UIControlEvents.TouchUpInside)
self.isChecked = false
}
func buttonClicked(sender: UIButton) {
isChecked = !isChecked
self.delegate?.checkBoxDidChange(self)
}}
is there any examples or a better way to do this?
If you don't want your button to change its checked property if it is already checked, just add conditional logic in your buttonClicked function.
func buttonClicked(sender: UIButton) {
if !isChecked {
isChecked = !isChecked
self.delegate?.checkBoxDidChange(self)
}
}
I think this is a bit complicate to do this.
What I would do :
#IBOutlet weak var siCheckBox: CheckBox!
#IBOutlet weak var noCheckBox: CheckBox!
override func viewDidLoad() {
super.viewDidLoad()
self.siCheckBox.setImage(checkedImage, forState: .Selected)
self.siCheckBox.setImage(uncheckedImage, forState: .Normal)
self.noCheckBox.setImage(checkedImage, forState: .Selected)
self.noCheckBox.setImage(uncheckedImage, forState: .Normal)
}
#IBAction func checkBoxAction(sender : UIButton) {
siCheckBox.isSelected = false
noCheckBox.isSelected = false
sender.isSelected = true
}
That way you don't even need to subclass your button and no delegate to set. Don't forget to link your two buttons to the checkbox action function ;)
I set one UILongPressGestureRecognizer to handle four different buttons in my view, how do I access which button is being clicked in my code?
My UILongPressGestureRecognizer looks like it:
#IBAction func editText(sender: UILongPressGestureRecognizer) {
textFieldInput.hidden = false
iphoneSaveCharName.hidden = false
}
And I Want to use Long Press so that I can edit the button text
EDIT 1:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var iphoneTableView: UITableView!
#IBOutlet weak var textFieldInput: UITextField!
#IBOutlet weak var iphoneSaveCharName: UIButton!
#IBOutlet weak var charOne: UILabel!
#IBOutlet weak var charTwo: UILabel!
#IBOutlet weak var charTree: UILabel!
#IBOutlet weak var charFour: UILabel!
#IBOutlet weak var test1: UIButton! //button that I am clicking on!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//Function I made so I can save the user input
#IBAction func iphoneSaveTextInput(sender: UIButton) {
let textData = textFieldInput.text
textFieldInput.hidden = true
iphoneSaveCharName.hidden = true
charTwo.text = textData
}
// This is the LongPress Action
#IBAction func editText(sender: UILongPressGestureRecognizer) {
textFieldInput.hidden = false
iphoneSaveCharName.hidden = false
func longPressMethod(gesture: UILongPressGestureRecognizer) {
println(gesture.view)
if gesture.view is UIButton {
let test1 = gesture.view as UIButton
println(test1)
}
}
}
}
Edit 2: Layout
Edit 3: New ViewController
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var iphoneTableView: UITableView!
#IBOutlet weak var textFieldInput: UITextField!
#IBOutlet weak var iphoneSaveCharName: UIButton!
#IBOutlet weak var charOne: UIButton!
#IBOutlet weak var charTwo: UIButton!
#IBOutlet weak var charThree: UIButton!
#IBOutlet weak var charFour: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func iphoneSaveTextInput(sender: UIButton) -> Void{
let textData = textFieldInput.text
textFieldInput.hidden = true
iphoneSaveCharName.hidden = true
}
#IBAction func editText(sender: AnyObject) {
if sender is UILongPressGestureRecognizer &&
sender.state == UIGestureRecognizerState.Began {
textFieldInput.hidden = false
iphoneSaveCharName.hidden = false
// func iphoneSaveTextInput(sender: UIButton){
// var textData = textFieldInput.text
// textFieldInput.hidden = true
// iphoneSaveCharName.hidden = true
//
// }
let button = sender.view as UIButton
println(button)
if button.tag == 1{
charOne.setTitle("textData", forState: .Normal)
} else if button.tag == 2{
charTwo.setTitle("textData2", forState: .Normal)
} else if button.tag == 3{
charThree.setTitle("textData3", forState: .Normal)
} else if button.tag == 4{
charFour.setTitle("textData4", forState: .Normal)
}
}
}
}
Answer:
This is the final view control:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var iphoneTableView: UITableView!
#IBOutlet weak var textFieldInput: UITextField!
#IBOutlet weak var iphoneSaveCharName: UIButton!
#IBOutlet weak var charOne: UIButton!
#IBOutlet weak var charTwo: UIButton!
#IBOutlet weak var charThree: UIButton!
#IBOutlet weak var charFour: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func iphoneSaveTextInput(sender: UIButton) -> Void{
let textData = textFieldInput.text
textFieldInput.hidden = true
iphoneSaveCharName.hidden = true
}
#IBAction func editText(sender: AnyObject) {
if sender is UILongPressGestureRecognizer &&
sender.state == UIGestureRecognizerState.Began {
textFieldInput.hidden = false
iphoneSaveCharName.hidden = false
// func iphoneSaveTextInput(sender: UIButton){
// var textData = textFieldInput.text
// textFieldInput.hidden = true
// iphoneSaveCharName.hidden = true
//
// }
let button = sender.view as UIButton
println(button)
if button.tag == 1{
charOne.setTitle("textData", forState: .Normal)
} else if button.tag == 2{
charTwo.setTitle("textData2", forState: .Normal)
} else if button.tag == 3{
charThree.setTitle("textData3", forState: .Normal)
} else if button.tag == 4{
charFour.setTitle("textData4", forState: .Normal)
}
}
}
}
I would mostly like to give you all a best answer since everybody helped me out! I had to create one Long Press for each button, otherwise code will get confused.
Your question has introduced me to a really cool feature, so thanks! :)
It turns out that if you attach a UILongPressGestureRecognizer to a UIButton in a storyboard and attach that button and gesture to an IBAction within your swift class, that IBAction method can recognize whether the touch is a tap or long press! Pretty cool, huh?
So first off, make sure that each UIButton has its own unique UILongPressGestureRecognizer; then you can edit your code like so, so that it's able to identify which button is being pressed and whether that press is either a simple tap or UILongPressGestureRecognizer:
// Connect both your button *and* its gestures to the
// `IBAction` method so that the function will be called
// no matter what kind of gesture it recognizes -- tap,
// long press, or otherwise.
#IBAction func buttonSelected(sender: AnyObject) {
// But to see if the gesture is a long press, you can
// simply check the sender's class and execute the code
// when the gesture begins.
if sender is UILongPressGestureRecognizer &&
sender.state == UIGestureRecognizerState.Began {
// These two lines are originally from your
// editText method
textFieldInput.hidden = false
iphoneSaveCharName.hidden = false
// Then to identify which button was long pressed you
// can check the sender's view, to see which button IBOutlet
// that gesture's view belongs to.
// Method #1:
let button = sender.view as UIButton
if button == thisButton {
} else if button == thatButton {
}
...
// Or you can check the gesture view's tag to see which
// button it belongs to (i.e. whichever button has a matching
// tag).
// Method #2:
let button = sender.view as UIButton
if button.tag == 1 {
} else if button.tag == 2 {
}
...
}
// Else if it's not a long press gesture, perform
// whatever action you'd like to accomplish during a
// normal button tap
else if !(sender is UILongPressGestureRecognizer) {
// These lines are originally from your
// iphoneSaveTextInput
let textData = textFieldInput.text
textFieldInput.hidden = true
iphoneSaveCharName.hidden = true
}
}
But if you want to continue to keep the UILongPressGestureRecognizer IBAction separate from the UIButton's IBAction (i.e. link the UIButtons to iphoneSaveTextInput: and your UILongPressGestureRecognizers to editText:), that should be OK too. Just keep your iphoneSaveTextInput: method as is, and update your editText: method like so:
// This is the LongPress Action
#IBAction func editText(sender: UILongPressGestureRecognizer) {
if sender.state == UIGestureRecognizerState.Began {
textFieldInput.hidden = false
iphoneSaveCharName.hidden = false
// Then to identify which button was long pressed you
// can check the sender's view, to see which button IBOutlet
// that gesture's view belongs to.
// Method #1:
let button = sender.view as UIButton
if button == thisButton {
} else if button == thatButton {
}
...
// Or you can check the gesture view's tag to see which
// button it belongs to (i.e. whichever button has a matching
// tag).
// Method #2:
let button = sender.view as UIButton
if button.tag == 1 {
} else if button.tag == 2 {
}
...
}
}
You don't want to use the same gesture recognizer across different views:
Can you attach a UIGestureRecognizer to multiple views?
The view property of the gesture recognizer is probably what you would want to check but you want different gesture recognizers for each view.
If you want, they could all be linked to the same selector, though, and you could access the incoming recognizer's view that way.
A general way to make a button have different actions based on how long you press it, looks like this (timer is a property),
#IBAction func buttonDown(sender: UIButton) { // connected to touchDown
timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: "handleTimer", userInfo: sender, repeats: false)
}
#IBAction func buttonUp(sender: UIButton) { // connected to touchUpInside
if timer != nil {
timer.invalidate()
println("change view")
}
}
func handleTimer() {
var button = timer.userInfo as UIButton
timer = nil
button.setTitle("New Title", forState: .Normal)
}