I have 3 buttons (can be images too) I need to select only one of them and the one that is selected changes color.
Some reference guide or help to implement.
see image of how it would be
Similar to Waze report: https://i.stack.imgur.com/dOiLe.jpg
The simplest way to do this is to use a UISegmentedControl. It consists of multiple buttons only one of which is selected at a time. It can be customized very heavily, so you can have the button images be one color when selected and another color when not selected.
This is a fairly standard UISegmentedControl:
This is a heavily customized UISegmentedControl:
As you can see, you can make the segments look however you like, and "the one that is selected changes color".
To implement it, example assuming you have 3 options in the segment, to receive the selected data you can use the following code in an IB:
#IBOutlet weak var optionSegment: UISegmentedControl!
var optionSelect = String()
#IBAction func indexChanged(_ sender: Any) {
switch optionSegment.selectedSegmentIndex
{
case 0:
optionSelect = "Select option 1"
print(optionSelect)
case 1:
optionSelect = "Select option 2"
print(optionSelect)
default:
optionSelect = "Select option 3"
print(optionSelect)
}
}
To use it outside of the function, you can use
let dataSelect = optionSegment.titleForSegment(at: optionSegment.selectedSegmentIndex)
print(dataSelect)
Related
I have a couple of UIKit pop-up menu buttons with identical menu items on the same screen in a Swift app. The buttons are built by calling a function that uses an array of strings to create the list of menu items.
The problem is that depending on the button's vertical position on the screen, the menu items may appear in the order specified by the function, or reversed. If the button is in the upper half of the screen, the menu items are listed in the correct order. If the button is in the lower half of the screen the menu items are listed in reverse order.
I would prefer the menu items to appear in the same order regardless of the button's position on the screen. I could check the button location and have the menu creation function reverse the order, but that seems kind of clunky. I am hoping there's a cleaner way to override this behaviour.
The code and array used to create the button menus:
let buttonMenuItems = ["Spring","Summer","Autumn","Winter"]
func createAttributeMenu(menuNumber: Int)->UIMenu {
var menuActions: [UIAction] = []
for attribute in buttonMenuItems {
let item = UIAction(title: attribute) { action in
self.updateMenu(menuID: menuNumber, selected: attribute)
}
menuActions.append(item)
}
return UIMenu(title: "", children: menuActions)
}
The result is this:
Versions I'm using now in testing: Xcode 14.1, iOS 16.1, but I have seen this behaviour on earlier versions as well. (back to iOS 14.x)
Starting with iOS 16, there is a .preferredMenuElementOrder property that can be set on the button:
case automatic
A constant that allows the system to choose an ordering strategy according to the current context.
case priority
A constant that displays menu elements according to their priority.
case fixed
A constant that displays menu elements in a fixed order.
Best I can tell (as with many Apple definitions), there is no difference between .automatic and .priority.
From the .priority docs page:
Discussion
This ordering strategy displays the first menu element in the UIMenu closest to the location of the user interaction.
So, we get "reversed" order based on the position of the menu relative to the button.
To keep your defined order:
buttonNearTop.menu = createAttributeMenu(menuNumber: 1)
buttonNearBottom.menu = createAttributeMenu(menuNumber: 2)
if #available(iOS 16.0, *) {
buttonNearBottom.preferredMenuElementOrder = .fixed
buttonNearTop.preferredMenuElementOrder = .fixed
} else {
// out of luck... you get Apple's "priority" ordering
}
I am using ios-charts in swift language. I'm wanting to show more data about each node when they are selected. A marker wouldn't have enough space for all the info I am wanting to display so I am wanting to display it all in a dedicated label on the ViewController itself. Is there any way to do this?
I got the chartValueSelected method working but am not sure how to utilize it for this.
Included ChartViewDelegate
&
chtChart.delegate = self
I have an array called textNotes thats corresponds to each data entry in the array and made a label called infoLabelChart
func chartValueSelected(_ chartView: ChartViewBase, entry:
ChartDataEntry, highlight: Highlight) {
let pos = NSInteger(entry.x)
infoLabelChart.text = "\(textNotes[pos])"
}
I've got five radio buttons, and selecting one should deselect the others.
I've been over a lot of the questions here about radio buttons in Swift, but they're either for iOS or outdated versions of Swift, because Xcode isn't offering me options like ".isSelected". I've got ".isEnabled" but clearly semantics matter here, because "enabled" isn't the same thing as "selected" and it shows.
Writing my code as a series of "if-else" statements along these lines:
func disableUnselectedButtons() {
if Button2.isEnabled == true {
Button1.isEnabled = false
Button3.isEnabled = false
Button4.isEnabled = false
Button5.isEnabled = false
}
}
results in a situation where I can select all five buttons, and can't DEselect any of them after another has been selected. I've tried variations of .on/.off as well, and can't find the right one for this situation.
It's also clumsy as heck to write a method with five if-else statements along those lines. So there's that.
What's the best way to go about implementing this?
If your radio buttons have the same superview and have the same action then they should work as expected.
To set the same action for each of your radio buttons you can do one of the following.
If you are using Storyboards, open both storyboard and related NSViewController swift file. Ctrl-drag your first radio button to the swift file. Then do the same for each of the other radio buttons ensuring you are dragging onto the function generated from the first Ctrl-drag.
If you are creating the radio buttons in code then set the action parameter in the init for each radio button to be the same.
Another way to approach this is to represent the buttons as a Set and then it's easy to iterate through them and configure their state. The below code actually allows for allowing multiple selections to support a scenario that wants to "select three of the six options".
let allButtons = Set(1...5). //or however many you want
func selectActiveButtons(_ activeButtons: Set<Int>, from allButtons: Set<Int>){
let inactive = allButtons.subtracting(activeButtons)
setButtonState(forButtons: inactive, isSelected: false)
setButtonState(forButtons: activeButtons, isSelected: true)
}
func setButtonState(forButtons buttons: Set<Int>, isSelected: Bool) {
buttons.forEach{
//remove below line and replace with code to update buttons in UI
print("Button \($0): \(isSelected ? "Selected" : "Unselected")")
}
}
// select buttons 1 & 3.
//If wanting a "classic" radio button group just use one value in the arrayLiteral.
selectActiveButtons(Set(arrayLiteral: 1,3), from: allButtons)
I want to only highlight a data point when the finger is on the chart, as soon as it lifts off the screen I want to call, or simple deselect the highlight.
func chartValueNothingSelected(chartView: ChartViewBase) {
print("Nothing Selected")
markerView.hidden = true
}
I've tried to override the touch ended but haven't gotten it to work.
You can turn off highlighting any bars/data all together using the highlightEnabled property.
Example of this is:
barChartView.data?.highlightEnabled = false
If you still want to be able to highlight values, but want them to automatically deselect after the touch has ended, I also found another function highlightValues(highs: [ChartHighlight]?) which says in the documentation..
Provide null or an empty array to undo all highlighting.
Call this when you want to deselect all the values and I believe this will work. Example of this could be:
let emptyVals = [ChartHighlight]()
barChartView.highlightValues(emptyVals)
Ref:
Charts Docs: highlightValues documentation
If you don't have to do anything with the tapped data you can use:
barChartView.data?.highlightEnabled = false
If you want to use the tapped data point without displaying the highlight lines, you can use the selection delegate (don't forget to add ChartViewDelegate to your class):
yourChartView.delegate = self // setup the delegate
Add delegate function:
func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
// do something with the selected data entry here
yourChartView.highlightValue(nil) // deselect selected data point
}
I have made printing functionality for custom NSView of NSPopover by the assigning the following action to button for this NSView in mainController:
#IBOutlet var plasmidMapIBOutlet: PlasmidMapView!
#IBAction func actionPrintfMap(sender: AnyObject)
{
plasmidMapIBOutlet.print(sender)
}
It is working, but the print window has no option for Paper Size and Orientation, see screenshot below.
What should I do to get these options in the print window?
And, how to make the NSView fitting to the printable area? Now it is not fitting.
I have figured out some moments, but not completely. So, I can setup the printing by the following code
#IBAction func actionPrintMap(sender: AnyObject)
{
let printInfo = NSPrintInfo.sharedPrintInfo()
let operation: NSPrintOperation = NSPrintOperation(view: plasmidMapIBOutlet, printInfo: printInfo)
operation.printPanel.options = NSPrintPanelOptions.ShowsPaperSize
operation.printPanel.options = NSPrintPanelOptions.ShowsOrientation
operation.runOperation()
//plasmidMapIBOutlet.print(sender)
}
But, I still have problem. From the code above I can get only orientation (the last, ShowsOrientation), but not both PaperSize and Orientation. How can I manage both ShowsPaperSize and ShowsOrientation?
Finally I have found the answer which is simple to write but it is not really obvious from apple documentation.
operation.printPanel.options.insert(NSPrintPanelOptions.showsPaperSize)
operation.printPanel.options.insert(NSPrintPanelOptions.showsOrientation)
The problem in the code originally posted is that options is being assigned twice, so the first value assigned, ShowsPaperSize is overwritten by the value ShowsOrientation. That's why you only see the ShowsOrientation option in the dialog.
By using multiple insert operations, you are adding options rather than overwriting each time. You can also do it this way which I think reads better:
operation.printPanel.options.insert([.showsPaperSize, .showsOrientation])
And finally, it also works to "set" the options, and by supplying the existing options as the first array value, you achieve the affect of appending:
operation.printPanel.options = [
operation.printPanel.options,
.showsPaperSize,
.showsOrientation
]
(The first array element operation.printPanel.options means that the old options are supplied in the list of new options.)