I want to Switch UIView by Clicking UISegmented Control but my Code is not working - swift

i want to Switch UIView by clicking Segmented Control but this Code is not working.
#IBOutlet weak var flightTypeSegCont: UISegmentedControl!
#IBAction func flightType(_ sender: UISegmentedControl) {
if(flightTypeSegCont.selectedSegmentIndex == 0)
{
self.direcrCard.isHidden = false
self.ViaCardView.isHidden = true
}
else
{
self.direcrCard.isHidden = true
self.ViaCardView.isHidden = false
}
}

Did you check if the function is getting called in XCode debugger? If not, connect IBAction from storyboard / xib to your function - valuechanged callout of UISegmentedControl.
If it is being called but views are not hidden as you want, check if they are having parent/child relationship. To check this in more details, go to XCode->View Debugging->Capture View hierarchy option to see the runtime UIView layout.

Related

macOS application like Photos.app on macOS

I'm trying to create a macOS app like Photos.app. The NSWindowController has a toolbar with a segmented control. When you tap on the segmented control, it changes out the the NSViewController within the NSWindowController.
What I have so far is an NSWindowController with an NSViewController. I have subclassed NSWindowController where I have the method that gets called whenever the user taps on the segmented control.
Essentially, whatever segment is clicked, it will instantiate the view controller that is needed and set it to the NSWindowController's contentViewController property.
Is this the correct way of doing it?
Also, the NSWindowController, I am thinking, should have properties for each of the NSViewControllers it can switch to that get lazy loaded (loaded when the user taps them and they get held around to be re-used to prevent re-initializing).
Code:
import Cocoa
class MainWindowController: NSWindowController
{
var secondaryViewController:NSViewController?
override func windowDidLoad()
{
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
#IBAction func segmentedControlDidChange(_ sender: NSSegmentedControl)
{
print("Index: \(sender.selectedSegment)")
if sender.selectedSegment == 3 {
if secondaryViewController == nil {
let viewController = storyboard?.instantiateController(withIdentifier: "SecondaryViewController") as! NSViewController
secondaryViewController = viewController
}
self.window?.contentViewController = self.secondaryViewController
}
}
}
I'm new to macOS development, however, I've been doing iOS for quite some time. If there is a better way, I'd like to know about it. Thanks!!!
to move the tab/segmented-control to the titlebar, you need:
add toolbar to window, and add the controls to the toolbar,
hide title:
class TopLevelWindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
if let window = window {
// reminder like style
// window.titlebarAppearsTransparent = true
window.titleVisibility = .hidden
// window.styleMask.insert(.fullSizeContentView)
}
}
}
now, toolbar will be merged into the top bar position.

Adding views with IBAction to a NSStackView crashes application

I want to use the NSStackView to stack views above each other, I also want them to de able to expand so I can't use the NSCollectionView if i understood it correctly.
So, in storyboard, I've created a NSStackView(embedded in scroll view) in the main view controller and a view controller that I want to fill it with:
The button will fill the stack view with ten views:
#IBOutlet weak var stackView: NSStackView!
#IBAction func redrawStackView(_ sender: Any) {
for i in 0..<10 {
let stackViewItemVC = storyboard?.instantiateController(withIdentifier: "StackViewItemVC") as! StackViewItemViewController
stackViewItemVC.id = i
stackView.addArrangedSubview(stackViewItemVC.view)
}
}
And the ViewController on the right simply looks like this:
class StackViewItemViewController: NSViewController {
var id: Int = -1
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
#IBAction func buttonPressed(_ sender: Any) {
debugPrint("StackViewItemViewController" + id.description + "pressed")
}
Running this small application works fine, every time I press the button ten more stack view items appears. But, when I have the audacity to press one of the buttons to the right the application crashes:
Where am I going wrong?
I have tried to work around the IBAction to verify that this what breaks, and the application will not crash if I subclass the button and make a "buttonDelegate" protocol with a function being called from mouseUp.
I guess the problem is that the viewController objects, which you create in the loop, are released immediately.
Even though the view is attached to the stackView, it's viewController is destroyed.
You can fix this issue by keeping a reference to each viewController.
You can do this by creating a new variable
var itemViewControllers = [StackViewItemViewController]()
and then add each newly created viewController to it:
itemViewController.append(stackViewItemVC)

Menubar with Storyboard - validateMenuItem not get called

I'm trying to setup a menubar Application using storyboard but my validateMenuItem method not get called.
I will try to explain what i did.
First i dragged a Menu Item in my Application Scene. Then one Object for my MenuController. Created a MenuController (MenuController.swift) and filled it with code. Back in my storyboard I set my Menu delegate to MenuController and MenuController Outlet to Menu. (I'm not totally sure whether i have set the delegates correctly.)
When i start the app, the menu icon appears and the first item title is set to test. But when i'm clicking the icon the validateMenuItem method not get called.
MenuController.swift
import Cocoa
class MenuController: NSObject {
var statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(-1)
#IBOutlet weak var statusMenu: NSMenu!
#IBOutlet weak var item1: NSMenuItem!
override func awakeFromNib() {
print("awakeFromNib")
self.item1.title = "Test"
let icon = NSImage(named: "menubarIcon")
statusItem.image = icon
statusItem.menu = statusMenu
}
override func validateMenuItem(menuItem: NSMenuItem) -> Bool {
print("validateMenuItem")
return true
}
}
Storyboard Menu Delegates
(source: picr.de)
Storyboard MenuController Delegates
(source: picr.de)
Has anybody an idea?
Greets from Austria!
The menu/UI validation mechanism does not query the menu's delegate but uses the item's target to determine the enabled state instead.
If the target is not explicitly set, it walks the responder chain.
To get basic validation, you have to make sure that the following things are setup:
"Auto Enables Items" is checked in Interface Builder (on by default)
You control-dragged the menu's action to the first responder
The menu's action is implemented in a class that is part of the responder chain (e.g. a view controller that manages a set of actions for your UI)
A basic implementation of validateUserInterfaceItem: could look like the following for an item with an action selector called test:
func validateUserInterfaceItem(anItem: NSValidatedUserInterfaceItem) -> Bool
{
if anItem.action() == Selector("test:") {
print("validating item \(anItem)")
return true
}
return true
}

NSButton state not changing

The following code works perfect in my sandbox:
#IBAction func filterClicked(sender: NSButton) {
println(sender.state)
if let clickEvent = NSApp.currentEvent! {
if Int(clickEvent.modifierFlags.rawValue) & Int(NSEventModifierFlags.ControlKeyMask.rawValue) != 0 {
if sender.state == NSOffState {
sender.state == NSOnState
}
}
}
println(sender.state)
}
The connected button is an On-Off button. So when it's on and I ctrl-click it it will stay on.
Unfortunately in my app where I really need this it does not work. I checked that in both sandbox and prod app the bindings/settings are identically for both buttons. The debugger shows that
sender.state == NSOnState
is simply not performed. state stays NSOffState. Gnawing my keyboard did not help. Any idea?
You are not assign any value to the button state.
sender.state = NSOnState
Update for Swift 4.2
sender.state = NSControl.StateValue.on
Changing state of a Radio Button (Check state) for swift 4:
#IBOutlet weak var checkedButton: NSButton!
checkedButton.state = NSControl.StateValue.off // State = off
checkedButton.state = NSControl.StateValue.on // State = on
I know this already has an accepted answer, but sharing my scenario in case it trips up someone else:
I had the same issue where I couldn't programmatically set the state for my button in a custom table view cell. MY issue, is that I was trying to set the state when my table first created the cell. Instead, I had to make sure to override the layout method in my custom cell and set the state there.
I had this in a CollectionViewItem...
I had an outlet for the favouriteButton...
class PictureCollectionViewItem: XCollectionViewItem
{
#IBOutlet var thumbnailView: NSImageView!
#IBOutlet var tagsView: NSTextField!
#IBOutlet var favouriteButton: NSButton!
...
}
I had linked the outlet to the Collection View Item object
but NOT linked it to the File's Owner...
As soon as I linked it to the File's Owner as well, ... it all worked.

Disable a Button

I want to disable a button (UIButton) on iOS after it is clicked. I am new to developing for iOS but I think the equivalent code on objective - C is this:
button.enabled = NO;
But I couldn't do that on swift.
The boolean value for NO in Swift is false.
button.isEnabled = false
should do it.
Here is the Swift documentation for UIControl's isEnabled property.
If you want the button to stay static without the "pressed" appearance:
// Swift 2
editButton.userInteractionEnabled = false
// Swift 3
editButton.isUserInteractionEnabled = false
Remember:
1) Your IBOutlet is --> #IBOutlet weak var editButton: UIButton!
2) Code above goes in viewWillAppear
The way I do this is as follows:
#IBAction func pressButton(sender: AnyObject) {
var disableMyButton = sender as? UIButton
disableMyButton.enabled = false
}
The IBAction is connected to your button in the storyboard.
If you have your button setup as an Outlet:
#IBOutlet weak var myButton: UIButton!
Then you can access the enabled properties by using the . notation on the button name:
myButton.enabled = false
Disable a button on Swift 3:
yourButton.isEnabled = false
For those who Googled "disable a button" but may have more nuanced use cases:
Disable with visual effect: As others have said, this will prevent the button from being pressed and the system will automatically make it look disabled:
yourButton.isEnabled = false
Disable without visual effect: Are you using a button in a case where it should look normal but not behave likes button by reacting to touches? Try this!
yourButton.userInteractionEnabled = false
Hide without disabling: This approach hides the button without disabling it (invisible but can still be tapped):
yourButton.alpha = 0.0
Remove: This will remove the view entirely:
yourButton.removeFromSuperView()
Tap something behind a button: Have two buttons stacked and you want the top button to temporarily act like it's not there? If you won't need the top button again, remove it. If you will need it again, try condensing its height or width to 0!
Swift 5 / SwiftUI
Nowadays it's done like this.
Button(action: action) {
Text(buttonLabel)
}
.disabled(!isEnabled)
You can enable/disable a button using isEnabled or isUserInteractionEnabled property.
The difference between two is :
isEnabled is a property of UIControl (super class of UIButton) and it has visual effects (i.e. grayed out) of enable/disable
isUserInteractionEnabled is a property of UIView (super class of UIControl) and has no visual effect although but achieves the purpose
Usage :
myButton.isEnabled = false // Recommended approach
myButton.isUserInteractionEnabled = false // Alternative approach
Let's say in Swift 4 you have a button set up for a segue as an IBAction like this #IBAction func nextLevel(_ sender: UIButton) {}
and you have other actions occurring within your app (i.e. a timer, gamePlay, etc.). Rather than disabling the segue button, you might want to give your user the option to use that segue while the other actions are still occurring and WITHOUT CRASHING THE APP. Here's how:
var appMode = 0
#IBAction func mySegue(_ sender: UIButton) {
if appMode == 1 { // avoid crash if button pressed during other app actions and/or conditions
let conflictingAction = sender as UIButton
conflictingAction.isEnabled = false
}
}
Please note that you will likely have other conditions within if appMode == 0 and/or if appMode == 1 that will still occur and NOT conflict with the mySegue button. Thus, AVOIDING A CRASH.
The button can be Disabled in Swift 4 by the code
#IBAction func yourButtonMethodname(sender: UIButon) {
yourButton.isEnabled = false
}
in order for this to work:
yourButton.isEnabled = false
you need to create an outlet in addition to your UI button.
Building on other answers here. I wanted to disable button for a few seconds to prevent double taps. Swift 5 version, xcode 13.4.1 likes this and has no warnings or errors.
#IBAction func saveComponent(_ sender: Any) {
let myButton = sender as? UIButton
myButton?.isEnabled = false
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(2000))
{
myButton?.isEnabled = true
}
}