Different functions for one bar button item - ios

I have a view controller with a segmented control(only two segments: Songs and Playlists) and a bar button item. When the songs segment is selected, I want the bar button item to perform action1, and when the playlists segment is selected, I want the bar button item to perform action2.
In an attempt to do this I created this function which I declared in the viewDidLoad and in the viewDidAppear:
func settearButton() {
let indice = segmentFiltroMusica.selectedSegmentIndex
switch indice {
case 0: //Canciones
btnAgregarMusica.action = #selector(irAAgregarCancionesVC)
btnAgregarMusica.target = self
case 1: // Playlists
btnAgregarMusica.action = #selector(irAAgregarPlaylistsVC)
btnAgregarMusica.target = self
default: print("")
}
}
However, the bar button item is only performing action1, no matter what segment is selected. How could I fix this?

I don't think you actually want to change the action of the button. Handle the button tap, check the state of your segment control, then call the appropriate method.
func settearButton() {
let index = segmentFiltroMusica.selectedSegmentIndex
switch index {
case 0:
irAagregarCancionesVC()
case 1:
irAggregarPlaylistsVC()
default:
break
}
}

First you should put your function in the class and not the viewDidLoad() or viewDidAppear(). You can make it private since you seem to use it only localy.
If you are using storyboards with a ViewController you probably know that you can drag actions and outlets of your segment and button onto your viewController Class.
Here is how I would do this, by using a Boolean value and change this to select between my actions:
private var myChoice: Bool = false
#IBOutlet weak var segment: NSSegmentedControl!
#IBAction func segmentAction(_ sender: Any) {
let index: Int = self.segment.selectedSegment
switch index {
case 0:
myChoice = true
case 1:
myChoice = false
default:
fatalError("This segment does not exist!")
}
}
#IBAction func buttonAction(_ sender: Any) {
if myChoice {
// Do case one
} else {
// Do case two
}
}
If you have more elements in the segment to choose from, take an enum instead of the Boolean. I kept your switch which is good if you will add an enum later, else you can just replace the content of the segmentAction() with:
myChoice = self.segment.selectedSegment == 0

Related

How to clear SearchBar result and show full data in tableview using Swift?

My Scenario, I am loading JSON data into tableview here I am maintaining two segment controller button for single tableview with search-bar. First segment button click to search I can get search result well and if I click segment button two there is also showing same search result. So, when I click segment one to two I need to clear search result and load normal data. Same scenario working well when I click close button within searchBar.
My Code
#IBAction func switchTableviewAction(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
print(“one”)
self.searchResultClear()
currentTableView = sender.selectedSegmentIndex
self.tableView.reloadData()
case 1:
print(“two”)
self.searchResultClear()
currentTableView = sender.selectedSegmentIndex
self.tableView.reloadData()
default:
break;
}
}
// MARK: Search Result Clear working but not clearing result
func searchResultClear() {
//self.searchBar.text = ""
//self.searchBar.showsCancelButton = false
//self.filteredLanguages.removeAll()
//self.tableView.reloadData()
}
Along with clearing search bar, you also need to remove the filtering from data source. By data source, I mean the array of objects you are showing in table view. You must be using a filter function with the filter text. If you want to clear the search bar, you also need to restore the original JSON data (the unfiltered one) and then call reloadData
You just need to call the searchBar textDidChange method with empty text when segment control selection is changed
#IBAction func switchTableviewAction(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
self.searchBar(self.searchBar, textDidChange: "")
case 1:
self.searchBar(self.searchBar, textDidChange: "")
default:
break;
}
}

How can i navigate to another page using picker view

i'm using here switch condition to navigate to another page using picker view and i already mentioned it in my controller but it's just navigate to one of the pages when i press on the second choice in picker view it takes me to the same page of the choice one.
i create a variable calling optionSelector and i gave him value 0 and i made the switch condition but still working on one page.
#IBAction func donePressed(_ sender: Any) {
mainPV.isHidden = true
doneBtn.isHidden = true
optionV.isHidden = true
switch optionSelector{
case 0:
FiltersController.instance.showAreaFilter(nc: self.navigationController!)
case 1:
FiltersController.instance.showTrainStations(nc: self.navigationController!)
case 2:
FiltersController.instance.showMapFilter(nc: self.navigationController!)
default:
FiltersController.instance.showResidintialFilter(nc: self.navigationController!)
}
}
You might not be updating the value of optionSelector on pickerView scroll.
Change optionSelector value on pickerView delegate method as:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
// put your logic here.
self.optionSelector = row
}
you might not have the correct value in optionSelector
You can use the selected value of the picker view by:
// Assuming you only have 1 component
// By default you only have 1 component
pickerView.selectedRowInComponent(0)
So effectively your done method will be:
#IBAction func donePressed(_ sender: Any) {
mainPV.isHidden = true
doneBtn.isHidden = true
optionV.isHidden = true
switch pickerView.selectedRowInComponent(0) {
case 0:
FiltersController.instance.showAreaFilter(nc: self.navigationController!)
break
case 1:
FiltersController.instance.showTrainStations(nc: self.navigationController!)
break
case 2:
FiltersController.instance.showMapFilter(nc: self.navigationController!)
break
default:
FiltersController.instance.showResidintialFilter(nc: self.navigationController!)
}
}

How do I make two UIButtons perform like radio buttons in Swift?

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
}

UISegmentedControl reload certain page

I'm using a third party library for my UISegmentedControl. The pages are initialised as following:
func carbonTabSwipeNavigation(carbonTabSwipeNavigation: CarbonTabSwipeNavigation, viewControllerAtIndex index: UInt) -> UIViewController {
switch index {
case 0:
return self.storyboard!.instantiateViewControllerWithIdentifier("FolderOverviewController") as! FolderOverviewController
case 1:
return self.storyboard!.instantiateViewControllerWithIdentifier("TopFoldersTab") as! TopFoldersTab
case 2:
return self.storyboard!.instantiateViewControllerWithIdentifier("CategoriesFolderTab") as! CategoriesFolderTab
default:
return self.storyboard!.instantiateViewControllerWithIdentifier("CategoriesFolderTab") as! CategoriesFolderTab
}
}
When I press the third segment, the user can go further down to see more details (via subviews on the same page). I would like the page to reload, every time I select the third segment again. (go back to the original CategoriesFolderTab page) . Currently I'm doing this with a ViewDidLoad(), but this is slowing down the app when you do it multiple times.
Is there a more correct way to do this? Thanks in advance
I think that calling viewDidLoad() is not the right approach for achieving this, instead, implement a new function that should contains code responsible for loading data in the UI components, for example:
override func viewDidLoad() {
super.viewDidLoad()
reloadUI()
}
func reloadUI() {
// filling UI components with desired data, such as:
// myLabel.text = "Hello World"
}
And somewhere in your code (where you want to reload), instead of calling viewDidLoad(), you should call reloadUI() method.
Hope this helped.
try this
Let folderOverVC = self.storyboard!.instantiateViewControllerWithIdentifier("FolderOverviewController") as! FolderOverviewController
Let topFoldersTab = self.storyboard!.instantiateViewControllerWithIdentifier("TopFoldersTab") as! TopFoldersTab
Let categoriesFolderTab = self.storyboard!.instantiateViewControllerWithIdentifier("CategoriesFolderTab") as! CategoriesFolderTab
func carbonTabSwipeNavigation(carbonTabSwipeNavigation: CarbonTabSwipeNavigation, viewControllerAtIndex index: UInt) -> UIViewController {
switch index {
case 0:
return folderOverVC
case 1:
return topFoldersTab
case 2:
return categoriesFolderTab
default:
return categoriesFolderTab
}
}
this initializes the view controllers once, so their respective viewDidLoad methods get called once initialized, not every time you tap a tab item

Can we make 1 UIButton for 2 action with swift?

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 {
...
}
}

Resources