I'm trying to avoid an app crash here... I have a button that will remove a segment from a UISegmentedControl. If that button is pressed and the user has the segment to be removed selected, the segment will remove and no selection will be highlighted. However, when another button is pushed that does an action that retrieves the selectedSegmentIndex, the app crashes.
In short: Is there any way to force the selection of a segment in a UISegmentedControl?
edit it seems as though the UISegmentedControl is returning a selectedSegmentIndex of -1 when no segment is selected... let's see what I can do from here.
Use yourSegmentname.selectedSegmentIndex = 1; or whichever segment you want.
This code is for swift 2.0
#IBOutlet weak var segmentcontroll: UISegmentedControl!
#IBAction func segmentneeded(sender: AnyObject)
{
if(segmentcontroll.selectedSegmentIndex==0)
{
self.view.backgroundColor=UIColor.purpleColor()
segmentcontroll.selectedSegmentIndex=UISegmentedControlNoSegment
}
else if(segmentcontroll.selectedSegmentIndex==1)
{
self.view.backgroundColor=UIColor.yellowColor()
segmentcontroll.selectedSegmentIndex=UISegmentedControlNoSegment
}
else
{
self.view.backgroundColor=UIColor.grayColor()
segmentcontroll.selectedSegmentIndex=UISegmentedControlNoSegment
}
}
Related
I'm a beginner in swift, I'm making an app in storyboard UIKit, and I need some help basically I need to set up a view controller that has buttons on it that when clicked add a string on the bottom of the VC, and if clicked again it will remove that same string. On the VC there going to be multiple buttons like this for options also on the bottom of the VC I need the label to update during the app also it should display like this for example. "Football","Basketball","Golf". It needs to be displayed just like that on the bottom with quotes and commas. I've to turn to make action buttons with a global array and put that inside each button but I can't figure out how to remove it when the button clicked again, also if you click the button again it'll add the same thing again so in the array you'll have two of the same strings. Anything would help.
P.S I need to do this in UIkit and Storyboard
You can make list of outlets to an array UIButton, handle list of actions when click into UIButton with a function. Using 'isSelected' property of UIButton to distinguish 'delete' or not.
class ViewController: UIViewController {
#IBOutlet weak var descriptionLabel: UILabel!
#IBOutlet var allButtons: [UIButton]!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func didTapButton(_ sender: UIButton) {
sender.isSelected.toggle()
_updateDescription()
}
private
func _updateDescription() {
descriptionLabel.text = allButtons
.filter { $0.isSelected }
.compactMap { $0.titleLabel?.text }
.map { "\"\($0)\"" }
.joined(separator: ", ")
}
}
I'm trying to learn iOS programming. To start I want to change the background color of my view when a button is clicked. My entire code looks as follows, but when I click the button no change happens. I'm using Xcode 13.1. Also I'm using a storyboard.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var myBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
NSLog("The app has launched")
}
#IBAction func changeColorClicked(_ sender: UIButton) {
self.myBtn.backgroundColor=UIColor.green
NSLog("I want to change color to green")
}
}
I see the NSLog message when I click, just no color change.
Check a few things:
First make sure your IBOutlet and IBAction are connected to the button itself.
You don't need to declare self here as the button as its already declared above and you don't need to call an instance of the view controller you're using to access the button.
You can also declare it like this to change the colour of the button in the function:
myBtn.backgroundColor = .green
To change the button's background colour when pressed.
Update on this thread if you can get it working.
I have an empty array, and I have #IBAction func test(_ sender: UIButton) with 25 different buttons attached to this func. how can I write the code for appending a button title to the array, when pressed?
someArray.append = (this part that I can't figure out?)
Since I don't know which button/buttons will be pressed I can't just write someArray.append = ("buttonTitle")
(ive googled and searched in here for hours, but I can't find the solution)
if let title = sender.title(for: sender.state) {
someArray.append(title)
}
For multiple UIButtons with single IBOutlet Action you can add tags for each UIButton.
So if you've used StoryBoard for UIButtons, so when you click on single UIButton - navigate to Attribute Inspector & add tag to each button. As shown in below fig.1.0
I've set all UIButtons with different title & tags.
Once you set tags, for all buttons, then programmatically you can identify which button is clicked via single - onClick function.
#IBAction func Click(_ sender: UIButton) {
if let title = sender.title(for: sender.state){
print(title)
//Here we are identifying which button is pressed. If I pressed UIButton.tag = 1 then I'm just printing it's title, else appending UIButton value in array.
if sender.tag == 1 {
print(sender.title(for: sender.state))
}
else{
self.someArray.append(title)
}
}
}
So, in this way you can identify all your UIButton actions within a single event action.
#IBOutlet weak var btnoutlet: UIButton!
if let title = btnoutlet.currentTitle {
someArray.append(title)
}
I have two UIButtons that I want to use to set an A/B value to a variable before I save data to a database. I want a button to become selected when tapped, and deselected when the other button is tapped, and vice versa. What is a good solution for accomplishing this programmatically or in Interface Builder?
In order to set an "A/B value" as you mention, the easiest option would be to use a UISwitch or -in the general case of possibly more than 2 options- a UISegmentedControl (as #rmaddy suggested in the question's comments) .
These controls have built-in the "choose just one out of many" functionality that you are looking for.
The drawbacks of the switch are:
It has to be either on or off (does not support a selection state of "neither A nor B")
You can't have separate title labels for each state.
If you still want two separate UIButton instances, you can:
Have references to both buttons in your view controller (#IBOutlets wired using Interface Builder), e.g.:
#IBOutlet weak var leftButton: UIButton!
#IBOutlet weak var rightButton: UIButton!
Implement the action method for both buttons in such a way that it sets the selected state of the tapped button, and resets the other one. For example:
#IBAction func buttonAction(sender: UIButton) {
if sender == leftButton {
leftButton.isSelected = true
rightButton.isSelected = false
} else if sender == rightButton{
leftButton.isSelected = false
rightButton.isSelected = true
}
}
This is a quick-and-dirty solution for just two buttons. If you want a generic radio group of n-buttons, there are open source solutions on GitHub, etc...
Try this.
First create both button separate #IBOutlet.
#IBOutlet weak var btnYes: UIButton!
#IBOutlet weak var btnNo: UIButton!
Set Both Button Tag Like this and you also set tag using storyboard.
override func viewDidLoad() {
super.viewDidLoad()
btnYes.tag = 1
btnNo.tag = 2
}
Implement Common #IBAction method for both buttons
#IBAction func btnYesNoTapped(_ sender: UIButton) {
if sender.tag == 1 {
self.IsBtnSelected(isSelect: true, with: self.btnYes)
}else {
self.IsBtnSelected(isSelect: true, with: self.btnNo)
}
}
Create Custome Method
func IsBtnSelected(isSelect:Bool,with sender:UIButton){
self.btnYes.isSelected = false
self.btnNo.isSelected = false
sender.isSelected = isSelect
}
you can use following function for creating a radio button behaviour, you have to btn outlet to be selected and array of both outlets to this function. instead ofcolor you can also compare images and set images. for getting a required value yo can create a variable in viewcontroller and assign this variable a value in IBAction of btn and you can call this function from IBAction.
func radioButton(_ btnToBeSelected: UIButton, _ btnArray: [UIButton]) {
for btn in btnArray {
if btn == btnToBeSelected {
btn.backgroundColor = UIColor.black
//selected btn
//You can also set btn images by
//btn.setImage(<#T##image: UIImage?##UIImage?#>, for: <#T##UIControlState#>)
} else {
btn.backgroundColor = UIColor.red
//not selected btn
}
}
}
In iOS , you would have to do it manually.See the below approaches,
Use a switch . Using a UISwitch would be better if the option indicates a on/off state.
Use a same method when the button is pressed. Whenever the method gets called deselect the other button/buttons and select the pressed button. You can use tags or keep a reference of the buttons to differentiate between them.
Lastly , keep different methods for each buttons . Just deselect the other buttons whenever the button is pressed.
You can follow the above approaches by using interface builder or programmatically.
You can achieve it like below
I have implemented it for dates which are in TableView you just need to do little modifications
enum filterDateSelectableOptions:Int {
case AssignDate
case DueDate
case CompletionDate
}
//Assign Date selected by default
var currentSelectedFilterDate:filterDateSelectableOptions = .AssignDate
Now
func btnRadioButtonTapped(sender:UIButton) {
switch sender.tag {
case kTableViewRow.AssignDate.rawValue:
self.currentSelectedFilterDate = .AssignDate
case kTableViewRow.DueDate.rawValue:
self.currentSelectedFilterDate = .DueDate
case kTableViewRow.CompletionDate.rawValue :
self.currentSelectedFilterDate = .CompletionDate
default:
break;
}
//sender.isSelected = !sender.isSelected
self.tblFilterList.reloadData()
}
in cellForRow I have
// THIS IS DIFFERENT ENUM SO +1 is required in my case
case .AssignDate,.DueDate,.CompletionDate :
let button = buttonRadioCircle
button.tag = row.rawValue
cell.accessoryView = button
button.addTarget(self, action: #selector(btnRadioButtonTapped(sender:)), for: .touchUpInside)
button.isSelected = self.currentSelectedFilterDate.rawValue + 1 == row.rawValue
}
I created a segmented control in my storyboard that looks like this:
Then I created an IBAction for when the control's value changes:
#IBAction func segmentValChanged(_ sender: UISegmentedControl) {
print("touched")
if (sender.selectedSegmentIndex == 0) {
sender.selectedSegmentIndex = 1;
}
else{
sender.selectedSegmentIndex = 0;
}
}
The only issue is that this function is never called!
When I click the Jokes (Beta) button, nothing happens.
However, when I created an IBOutlet for the control and tried to change the selected segment in my viewDidLoad(), it worked:
segmentedController.selectedSegmentIndex = 1
I know I probably missed something obvious, since I've never used a segmented control before.
Thanks so much if anyone can point out what this is.
Cheers!
import UIKit
import Alamofire
class ViewController: UIViewController {
var currentImage: CurrentImage!
var parameters: Parameters!
#IBOutlet weak var segmentedController: UISegmentedControl!
#IBAction func segmentValChanged(_ sender: UISegmentedControl) {
print("touched")
if (sender.selectedSegmentIndex == 0) { // switch to 1
sender.selectedSegmentIndex = 1;
}
else{
sender.selectedSegmentIndex = 0;
}
}
override func viewDidLoad() {
super.viewDidLoad()
segmentedController.selectedSegmentIndex = 1
self.segmentedController.addTarget(self, action: #selector(segmentValChanged(_:)), for: .valueChanged)
}
}
And this is what it looks like when I right click the view:
Whenever I see this it is almost always the same problem... If the segmented control is being drawn outside of its parent view, then it will not respond to taps. This is most likely the problem you are having. (This can also happen with UIButtons.)
Ways to test if this is the problem:
set clipsToBounds of the segmented control's parent to true. If the control no longer shows on the screen, then it is being drawn outside of it's parent view. segmentedControl.superview?.clipsToBounds = true
add a border to the segmented control's parent. If the control is being drawn outside the border then there you go. segmentedControl.superview?.layer.borderWidth = 1
Solve the problem by expanding the size of the parent view so the control is being drawn within it.
On a side note, your IBAction is incorrect. When the value changed action is called, the segmented control will already have changed its value and the new segment will be highlighted. You don't have to do it manually. This is another indicator that your control isn't being drawn in the bounds of its parent view.