UISegmentedControl with multiple row - ios

I need a UISegmentedControl with 2 row, I could not implement it.
I dont want to use 2 different UISegmentedControl. Are there any solution to this problem? How to implement UISegmentedControl with two rows?

'UISegmentedControl' does not support multiple rows. If you need it you'll have to build it yourself or find a third party library that offers it.
As Helium suggests in his/her comment, you could create a custom control that internally manages 2 or more segmented controls and handles changing states between them.
Truth be told a segmented control is not that complicated. It wouldn't be that hard to create a custom 2D segmented control. If this is a key need then you might want to go that route.

Basically, you will need to have an IBAction and IBOutlet on each of your segmented control.
Code the IBAction such that clicking on one of the segmented control will set the IBOutlet's selectedSegmentIndex of the other segmented controls(which are not selected) to UISegmentedControlNoSegment. This creates the illusion that the segmented controls are linked.
Then getting the correct info of which segmented control value is selected is simply gathering all the index of the segmented control into one constant.
#IBOutlet weak var segment1: UISegmentedControl!
#IBOutlet weak var segment2: UISegmentedControl!
#IBOutlet weak var segment3: UISegmentedControl!
#IBAction func FirstSecond(_ sender: UISegmentedControl) {
segment2.selectedSegmentIndex = UISegmentedControlNoSegment
segment3.selectedSegmentIndex = UISegmentedControlNoSegment
}
#IBAction func ThirdFourth(_ sender: UISegmentedControl) {
segment1.selectedSegmentIndex = UISegmentedControlNoSegment
segment3.selectedSegmentIndex = UISegmentedControlNoSegment
}
#IBAction func FifthSixth(_ sender: UISegmentedControl) {
segment1.selectedSegmentIndex = UISegmentedControlNoSegment
segment2.selectedSegmentIndex = UISegmentedControlNoSegment
}
let segmentvalue = ["First","Second","Third","Fourth","Fifth","Sixth"]
#IBAction func FirstSecond(_ sender: UISegmentedControl) {
segment2.selectedSegmentIndex = UISegmentedControlNoSegment
segment3.selectedSegmentIndex = UISegmentedControlNoSegment
let valueINeed = segmentvalue[segment1.selectedSegmentIndex]
}
#IBAction func ThirdFourth(_ sender: UISegmentedControl) {
segment1.selectedSegmentIndex = UISegmentedControlNoSegment
segment3.selectedSegmentIndex = UISegmentedControlNoSegment
let valueINeed = segmentvalue[segment2.selectedSegmentIndex + 2]
}
#IBAction func FifthSixth(_ sender: UISegmentedControl) {
segment1.selectedSegmentIndex = UISegmentedControlNoSegment
segment2.selectedSegmentIndex = UISegmentedControlNoSegment
let valueINeed = segmentvalue[segment3.selectedSegmentIndex + 4]
}
Full Details availabe here: multi row segemented control in swift

Related

How to transfer information from one IBAction to another

The code should work as follows: On one View I click tag button and tagButtonPressed IBAction should set tag variable to sender.tag of the tag button. It works well. Then user should click 'send' button and sharePressed IBAction should use the tag variable which equals to sender.tag of the 'tag' button, and print the updated value of tag variable. Unfortunately it doesn't work.
import UIKit
class ShareViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
var tag : Int = 1
#IBOutlet weak var shareTextField: UITextView!
#IBAction func tagButtonPressed(_ sender: UIButton) {
tag = sender.tag // lets say sender.tag = 4
print(tag) // It prints 4
}
#IBAction func sharePressed(_ sender: Any) {
print(tag) // it prints 1 and i want it to print also 4
}
}
Your code is correct. Somewhere else (not shown) you're re-setting the tag value to 1.

Using UIButton as a Switch

I am trying to use a UIButton as a switch. When the button is tapped, the button image should change to (atcs.png) and state should be (.selected).
When image is tapped again, the button image should again to (actns.png) and state should be (.normal).
Below is an example of my current code:
#IBOutlet weak var atcBtn: UIButton!
#IBAction func atcTapped(_ sender: UIButton) {
if atcBtn.isSelected {
atcBtn.setImage(UIImage(named: "atcs.png"), for:.selected)
} else {
atcBtn.setImage(UIImage(named: "atcns.png"), for:.normal)
}
}
This somehow isn't working. Is there anything missing? Tried almost every solution listed on here, but nothing.
First, move your setImage code to viewDidLoad. There's no reason to repeatedly set these images:
atcBtn.setImage(UIImage(named: "atcs.png"), for:.selected)
atcBtn.setImage(UIImage(named: "atcns.png"), for:.normal)
Next, toggle the isSelected property when the button is tapped:
#IBAction func atcTapped(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
}
Also of note - use sender instead of hardcoding atcBtn.

Negating a button when an array is empty

Im developing in Swift and I am displaying one string from an array by clicking a button. However, after the array is empty and the last string of the array is displayed, I want the user to be unable to click on the button since there are no more strings to display and the array is empty. So far I have crafted code to where the button is disabled after the array is empty but it stays disabled even after I had more strings to the array (by clicking another button). Any help would be highly appreciated.
#IBOutlet weak var selectedChoice: UILabel!
#IBOutlet weak var field: UITextField!
var choices = [String]()
//first button that adds string to array
#IBAction func addToChoices(_ sender: Any) {
choices.append(field.text!)
print(choices)
print(choices.count)
}
//button that I want to disable once 'choices.isEmpty' but enable it again after more strings are added to 'choices'
#IBAction func shuffleTilExhuasted(_ sender: Any) {
let button = sender as? UIButton
let rand = Int(arc4random_uniform(UInt32(choices.count)))
selectedChoice.text = choices[rand]
choices.remove(at: rand)
switch choices.isEmpty {
case true:
button?.isEnabled = false
case false:
button?.isEnabled = true
}
Re enable it when add , create IBOutlet of the button
//first button that adds string to array
#IBAction func addToChoices(_ sender: Any) {
choices.append(field.text!)
self.btn.isEnabled = true
print(choices)
print(choices.count)
}
OR use didSet with the array
var choices:[String] = []
{
didSet {
self.btn.isEnabled = choices.isEmpty
}
}

Use Segmented Control Swift 3

I have searched the web and youtube about segmented control, but I only find examples of how to change to a different view.
My goal is to take the selected value from the segmented control and use it in the action on another button.
I will try to explain what I mean :
#IBAction func segmentetControll(_ sender: UISegmentedControl) {
value 1
value 2
value 3
}
#IBAction func calculateButton(_ sender: Any) {
if value 1 {
do this
}
else if value 2 {
Do that
}
else if value 3 {
Do thids
}
You need to connect it via #IBOutlet to file.
Then you can use its index to do whatever you want.
#IBOutlet var segmentedControl: UISegmentedControl!
#IBAction func calculateButton(_ sender: Any) {
let index = segmentedControl.selectedSegmentIndex
//...
}
Putting the code in the IBAction method connected via the storyboard or Xib file is the correct approach. You can use strong types when hooking up the action to the control and write code such as:
#IBAction func calculateButton(_ sender: UISegmentedControl) {
switch(sender.selectedSegmentIndex){
case 1:
// Do something
case 2:
// Do something
case 3:
// Do something
default:
break
}
}
You would need to create an #IBOutlet var segmentedControl: UISegmentedControl? property that connects to the segmented control in the Interface Builder, and then in the calculateButton method you can switch over segmentedControl.selectedSegmentIndex. Let me know if you need further explanation.

Swift - Segmented control - Switch multiple views

Until now I still can't figure how to switch multiple views in one view controller. My storyboard is like this one.
Right now I want to embed two views inside my view controller.
My code for segmented control to switch two views in one view controller so far.
import UIKit
class PopularHistoryViewController: UIViewController {
#IBOutlet weak var segmentedControl: UISegmentedControl!
#IBAction func indexChanged(sender: UISegmentedControl) {
switch segmentedControl.selectedSegmentIndex
{
case 0:
NSLog("Popular selected")
//show popular view
case 1:
NSLog("History selected")
//show history view
default:
break;
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
Another thing, If I put two views inside my controller, what is best practice to differentiate it?
If you want to do UI layout in Xcode for the two overlapping subviews, a better solution is to use two UIContainerViewController, and use the same way of setting the hidden property as suggested in the above answer.
You can use the isHidden property of the UIView to show/hide your required views.
First you have to link both views to IBOutlets through the Interface builder
#IBOutlet weak var historyView: UIView!
#IBOutlet weak var popularView: UIView!
#IBAction func indexChanged(_ sender: UISegmentedControl) {
switch segmentedControl.selectedSegmentIndex {
case 0:
historyView.isHidden = true
popularView.isHidden = false
case 1:
historyView.isHidden = false
popularView.isHidden = true
default:
break;
}
}
Note: it was named hidden in Swift 1 and 2.
First of all create two outlets and connect hose to the views in your ViewController.
#IBOutlet weak var firstView: UIView!
#IBOutlet weak var secondView: UIView!
And Change the code like:
#IBAction func indexChanged(sender: UISegmentedControl)
{
switch segmentedControl.selectedSegmentIndex
{
case 0:
firstView.hidden = false
secondView.hidden = true
case 1:
firstView.hidden = true
secondView.hidden = false
default:
break;
}
}
If you don't want to create Outlets, assign the views individual tags (Say 101 and 102) and you can do it like:
#IBAction func indexChanged(sender: UISegmentedControl)
{
switch segmentedControl.selectedSegmentIndex
{
case 0:
self.view.viewWithTag(101)?.hidden = false
self.view.viewWithTag(102)?.hidden = true
case 1:
self.view.viewWithTag(101)?.hidden = true
self.view.viewWithTag(102)?.hidden = false
default:
break;
}
}
Add both views to the view controller in the story board and set one of them to be hidden = yes or alpha = 0. When your index changed function gets called set the current view on screen to hidden = yes/alpha of 0 and set the previously hidden view to hidden = no/alpha = 1. This should achieve what you want.
If it is a simple view, not a part of the screen, you can indeed use isHidden property of two subviews of your view controller view. But I don't like this approach because it's hard to understand latter what is going on with your nib when all of the subviews are in one pile.
I would add and remove those two views as child view controllers programmatically. It's the cleanest way there is, in my opinion.
But even if you decided to go with just views, don't put them directly on view controller's view. Use nibs, preferably with owner class. And in many cases consider adding and constraint them programmatically. It's more code, but also cleaner and conserves resources.
#IBAction func acSegmentAction(_ sender: Any) {
switch acSegmentedControl.selectedSegmentIndex {
case 0:
// print("addressview selected")
addressView.isHidden = false
contactProviderView.isHidden = true
case 1:
//print("contact provider selected")
addressView.isHidden = true
contactProviderView.isHidden = false
default:
break;
}
}
So what is written above does not work for me, so I figured out myself in Xcode 11 with Swift 5.
(view1 = historyView, view2 = popularView)
#IBOutlet weak var view1: UITableView!
#IBOutlet weak var view2: UITableView!
#IBAction func segmentedControlChanged(_ sender: Any) {
func showView1() {
view1.isHidden = false
view2.isHidden = true
}
func showView2() {
view1.isHidden = true
view2.isHidden = false
}
guard let segmentedControl = sender as?
UISegmentedControl else { return }
if segmentedControl.selectedSegmentIndex == 0 {
showView1()
}
else {
showView2()
}
}
Maybe this helps anyone.

Resources