Is it possible to achieve this using swift?
I would like to make many checkboxes inside an UIView in swift
Simple just check for the image loaded on button and take appropriate action see below code:
// declare bool
var unchecked = true
#IBAction func tick(sender: UIButton) {
if unchecked {
sender.setImage(UIImage(named:"checked.png"), forControlState: .Normal)
unchecked = false
}
else {
sender.setImage( UIImage(named:"unchecked.png"), forControlState: .Normal)
unchecked = true
}
}
Note:
You need to use two different images named as checked and unchecked.
Then above code is used for separate button (checkmarks) you need to create.
Simply add a UIButton on the board. Remove the text and add an image for a unselected(default) state and a selected state.
On the ViewController add an #IBAction for the function as follows:
#IBAction func check(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
}
make a UI button
set an uncheckedImage for your button for UIControlStateNormal and a checkedImage for your UIControlStateSelected.
Now on taps the button will change its image and alternate between checked and unchecked image.
Use for loop to create multiple checkboxes and set the x position.Set tag for each to identify when tap.
You can easily create simple checkbox control in swift like these...
#IBAction func btn_box(sender: UIButton) {
if (btn_box.selected == true)
{
btn_box.setBackgroundImage(UIImage(named: "box"), forState: UIControlState.Normal)
btn_box.selected = false;
}
else
{
btn_box.setBackgroundImage(UIImage(named: "checkBox"), forState: UIControlState.Normal)
btn_box.selected = true;
}
}
Swift 4
let checkedImage = UIImage(named: "checked")! as UIImage
let uncheckedImage = UIImage(named: "unchecked")! as UIImage
#IBAction func tickavtion(_ sender: Any) {
if unchecked {
(sender as AnyObject).setImage(checkedImage, for: UIControlState.normal)
unchecked = false
}
else {
(sender as AnyObject).setImage(uncheckedImage, for: UIControlState.normal)
unchecked = true
}
}
which kind of checkbox you intend to make? Multi-selection or radio btn? Have you tried doing it in OC? I advice you 1) to add the btns into an array after you initialized them. 2) In the touch event you traverse the btns to implement your logic.
Related
I have buttons in the storyboard that I put into a Referencing Outlet Collection. I'm using UITapGestureRecognizer and UILongPressGestureRecognizer for all of these buttons, but how can I print exactly which button gets tapped? Bellow is what I tried but doesn't work. I get an error that says "Value of type 'UILongPressGestureRecognizer' has no member 'tag'." I'm trying to build the button grid for the Minesweeper game. Thank you for your help.
class ViewController: UIViewController {
#IBOutlet var testButtons: [UIButton]! // There are 100 buttons in this array
override func viewDidLoad() {
super.viewDidLoad()
let testButtonPressed = UILongPressGestureRecognizer(target: self, action: #selector(testPressed))
testButtonPressed.minimumPressDuration = 0.5
// These indexes are just to test how to recognize which button gets pressed
testButtons[0].addGestureRecognizer(testButtonPressed)
testButtons[1].addGestureRecognizer(testButtonPressed)
}
#objc func testPressed(_ sender: UILongPressGestureRecognizer) {
print("Test button was pressed")
print(sender.tag) // THIS DOESN'T WORK, BUT CONCEPTUALLY THIS IS WHAT I WANT TO DO
}
This error occurs because UILongPressGestureRecognizer object has no tag property
You can access sender's button in a way like that:
#objc func testPressed(_ sender: UILongPressGestureRecognizer) {
guard let button = sender.view as? UIButton else { return }
print(button.tag)
}
I think that the best solution to handle button's actions is to add #IBAction
(you can add it like #IBOutlet with a minor change - set Action connection type)
And then in #IBAction block you cann access all button properties (like tag and others)
instead of using gesture I think it would be better to use #IBAction and connect the buttons With it here is a small example
UILongPressGestureRecognizer which is a subclass of UIGestureRecognizer, can be used only once per button or view. Because UILongPressGestureRecognizer has only a single view property. In your code, it will always be testButtons[1] calling the testPressed action. So you have to first modify the viewDidLoad code like this :-
for button in testButtons {
let testButtonPressed = UILongPressGestureRecognizer(target: self, action: #selector(testPressed))
testButtonPressed.minimumPressDuration = 0.5
button.addGestureRecognizer(testButtonPressed)
button.addGestureRecognizer(testButtonPressed)
}
Then you can access the button from testPressed like this (I hope you've already set the tag in the storyboard) :-
#objc func testPressed(_ sender: UILongPressGestureRecognizer) {
if sender.state == .began {
if let button = sender.view as? UIButton {
print(button.tag)
}
}
}
You need to set tags before pressing!
On the viewDidLoad() method you must add something like:
testButtons.enumerated().forEach {
let testButtonPressed = UILongPressGestureRecognizer(target: self, action: #selector(testPressed))
testButtonPressed.minimumPressDuration = 0.5
$0.element.addGestureRecognizer(testButtonPressed)
$0.element.tag = $0.offset
}
And when the long press is receiving you need to get a tag from view not from the sender!
print(sender.view?.tag)
Since a gesture recognizer should only be associated with a single view, and doesn't directly support using an identity tag to match it with buttons. When creating an array of buttons for a keyboard, with a single gesture response function, I found it easier to use the gesture recognizer "name" property to identify the associated button.
var allNames: [String] = []
// MARK: Long Press Gesture
func addButtonGestureRecognizer(button: UIButton, name: String) {
let longPrssRcngr = UILongPressGestureRecognizer.init(target: self, action: #selector(longPressOfButton(gestureRecognizer:)))
longPrssRcngr.minimumPressDuration = 0.5
longPrssRcngr.numberOfTouchesRequired = 1
longPrssRcngr.allowableMovement = 10.0
longPrssRcngr.name = name
allNames.append(name)
button.addGestureRecognizer(longPrssRcngr)
}
// MARK: Long Key Press
#objc func longPressOfButton(gestureRecognizer: UILongPressGestureRecognizer) {
print("\nLong Press Button => \(String(describing: gestureRecognizer.name)) : State = \(gestureRecognizer.state)\n")
if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
if let keyName = gestureRecognizer.name {
if allNames.contains(keyName) {
insertKeyText(key: keyName)
} else {
print("No action available for key")
}
}
}
}
To implement, call the addButtonGestureRecognizer function after creating the button, and provide a name for the button (I used the button text) e.g.
addButtonGestureRecognizer(button: keyButton, name: buttonText)
The button name is stored in the "allNames" string array so that it can be matched later in "longPressOfButton".
When the button name is matched in the "longPressOfButton" response function, it passes it to "addKeyFunction" where it is processed.
I'm trying to identify the clicked radio button using the Interface builder identifier.
#IBAction func text_radio_changed(_ sender: Any) {
let button:NSButton = sender as! NSButton
let id:String = button.accessibilityIdentifier()
print("===========>"+id)
}
But the console keeps printing this
===========>
There is no identifier
button.accessibilityIdentifier is the Accessibility Identity Identifier. The Identity Identifier is button.identifier.
#IBAction func text_radio_changed(_ sender: Any) {
let button:NSButton = sender as! NSButton
let id:String = button.identifier!.rawValue
print("===========>"+id)
}
On your code you are actually trying to access the accessibility identifier which is a different thing. To identify the radio button you should use tags. Set a tag for the button and then read it like this.
#IBAction func text_radio_changed(_ sender: Any) {
let button:NSButton = sender as! NSButton
let id:Int = button.tag
print("===========>"+id)
}
Note: You can actually do use the accessibility id to do the same thing. Check this other similar post.
Update: The answer by "Willeke" seems better (if it works), I am used to developing for iOS and I wasn't aware there is an identifier property for NSButtons.
I'm wondering if there is a more efficient way to code an action that is the same with the exception of which button has been pressed and which item in a struct it relates to. Basically, I have a struct of 10 variables all of which are a boolean type and I have 10 buttons. When the user presses the button, I want to check whether it has already been pressed (using the struct) and then change the background of the button depending on the state and reverse the state. I've copied my current code for one of the buttons but thought I should be able to avoid doing this 10 times!
#IBAction func architectureButtonPressed(_ sender: Any) {
if myInterests.architecture {
myInterests.architecture = false
architectureButton.setBackgroundImage(imageUncheckedNarrow, for: .normal)
} else {
myInterests.architecture = true
architectureButton.setBackgroundImage(imageCheckedNarrow, for: .normal)
}
}
Well one simple way is to have each UIButton point to the same architectureButtonPressed IBAction method. Since the button that's pressed is passed into the method (sender) you can consult it's tag property to know the index of which field in your struct should be updated. (And then you might want to change your struct to just store an array of 10 bools, but up to you).
Then for each UIButton, whether programmatically in storyboard or nib, you'd assign the appropriate index value to the button's tag field.
Create yours IBOutlet for each button.
Create a array and store all buttons like : var arrayButtons : [UIButton] = []
arrayButtons.append[button1]
arrayButtons.append[button2]
...
Create a array of booleans to store true/false: var arrayBools : [Bool] = [] and initialize if some value.
Note that the indexes of the arrayButtons and arrayBools must be same related.
Create selector function to listen touch buttons.
button.addTarget(self, action: #selector(my_func), for: .touchUpInside)
#objc func my_func(_ sender : UIButton) {
for i in 0...arrayButtons.size-1 {
if arrayButtons[i] == sender {
if arrayBooleans[i] {
arrayBooleans[i] = false
arrayButtons[i].setImage()
} else {
arrayBooleans[i] = true
arrayButtons[i].setImage()
}
}
}
}
My suggestion is to manage the images in Interface Builder via State Config (Default/Selected)
Then assign an unique tag starting from 100 to each button and set the isSelected value in the IBAction to the corresponding struct member in a switch statement:
#IBAction func buttonPressed(_ sender: UIButton) {
switch sender.tag {
case 100: myInterests.architecture = sender.isSelected
case 101: myInterests.art = sender.isSelected
...
default: break
}
}
Alternatively use Swift's native KVC with WriteableKeypath
let keypaths : [WritableKeyPath<Interests,Bool>] = [\.architecture, \.art, \.fashion, \.history, \.localCulture, \.music, \.nature, \.shopping, \.sport, \.anything]
#IBAction func buttonPressed(_ sender: UIButton) {
let index = sender.tag - 100
let keypath = keypaths[index]
myInterests[keyPath: keypath] = sender.isSelected
}
I’m new to swift so I am stumped on something that is probably very simple.
I want to have checkboxes for each day of the week and be able to toggle their states a bit like the standard Apple clock app alarm repeat page. I am using a subclass borrowed from https://github.com/kenthinson/checkbox/ to create a set of checkboxes. All that works like a charm in the storyboard but now I am struggling with how to refer to the subclass checkbox ‘state’ in my view controller to actually do something.
So here is the subclass:
import UIKit
class checkBox: UIButton {
//images
let checkedImage = UIImage(named: "checkBoxChecked")
let unCheckedImage = UIImage(named: "checkBoxUnchecked")
//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: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
self.isChecked = false
}
func buttonClicked(sender:UIButton) {
if(sender == self){
if isChecked == true{
isChecked = false
}else{
isChecked = true
}
}
}
}
Here is an outlet example:
#IBOutlet weak var sun: checkBox!
Here is my empty array ready to be appended (working):
var daysArray:[String] = []
Here is an example action:
#IBAction func setSunday(sender: checkBox) {
if (****what do I do here to retrieve the button state?****) {
daysArray.append("0")
print(daysArray) // Check the array is working then delete
} else {
daysArray.removeAtIndex(0)
print(daysArray) // Check the array is working then delete
}
}
If I can get this working then I can apply to all days of the week and make the state of the array persistent using NSUserDefaults.
Hope you guys can help.
Use sender.isChecked to retrieve the state:
#IBAction func setSunday(sender: checkBox) {
if sender.isChecked {
daysArray.append("0")
print(daysArray) // Check the array is working then delete
} else {
daysArray.removeAtIndex(0)
print(daysArray) // Check the array is working then delete
}
}
How do i make a UIButton do something different every time it is pressed in swift. Ive tried making two buttons that overlap and one hides when it is clicked Didn't work though.
EDIT: nevermind i found i could do this for a mute/play button
If backgroundaudio.play
Backgroundaudio.pause
Else
Backgroundaudio.play
You can do it in two different ways:
Changing the target of the button:
Adding a target:
button.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
Removing a target:
button.removeTarget(nil, action: nil, forControlEvents: .AllEvents)
Or have a logical statement inside your action function:
button.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
func buttonAction(sender: UIButton!)
{
//your conditions go here
}
For example: To do something every other time you could write:
func oneThing() {
// Do your stuff
}
func otherThing() {
// Do other stuff
}
var shouldDoOtherThing = false
#IBAction func clicked(sender: UIButton) {
if shouldDoOtherThing {
otherThing()
} else {
oneThing()
}
shouldDoOtherThing = !shouldDoOtherThing
}
You could also just do the stuff you want to do inside the if statement like
var shouldDoOtherThing = false
#IBAction func clicked(sender: UIButton) {
if shouldDoOtherThing {
// Do other stuff
} else {
// Do your stuff
}
shouldDoOtherThing = !shouldDoOtherThing
}
Or you can use anything else that changes what code should execute (they are called Control Statements)
I just tested this out. You'll only need one button.You can do as many random things as you want
#IBAction func button_click(sender: AnyObject) {
var randomNumber = Int(arc4random_uniform(5) + 1) // generates random number 1 - 5
println(randomNumber)
switch randomNumber { // perform method depending on what random number was generated
case 1 :
funcOne() // Run this method
println("Pressed 1")
case 2:
funcTwo() // Runs this method
println("Pressed 2")
case 3:
funcThree() // Runs this method
println("Pressed 3")
case 4:
funcFour() // Runs this method
println("Pressed 4")
case 5:
funcFive() // Runs this method
println("Pressed 5")
default:
println("do nothing")
}
}