Fade out NSButton using NSAnimationContext - swift

I have a simple Swift macOS app (using Xcode 8.2.1) that contains a single NSButton. When I click the button I would like it to fade out over a specified period. I thought I could use NSAnimationContext but no matter what value I set the context duration the button fades out almost immediately. Is this not the right way to do this?
class ViewController: NSViewController {
#IBOutlet weak var basicButton: NSButton!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func basicButtonClicked(_ sender: NSButton) {
NSAnimationContext.runAnimationGroup({ (context) in
context.duration = 10.0
self.basicButton.animator().alphaValue = 1
}) {
self.basicButton.animator().alphaValue = 0
}
}
}

I misunderstood how the animator values worked during the animation. The right way to set this up is:
#IBAction func basicButtonClicked(_ sender: NSButton) {
NSAnimationContext.runAnimationGroup({ (context) in
context.duration = 10.0
// Use the value you want to animate to (NOT the starting value)
self.basicButton.animator().alphaValue = 0
})
}

Related

Why is the Button enable not working when TextView has contents?

Likely a very simple rookie mistake going on here but I'm trying to make sure a button is disabled until a TextView has text in it.
I set
Button.isEnabled = false
and then added this code. I've tried variations of this code in various ways, I'm seemingly unable to attach it to the textView itself, I can't imagine why this wouldn't be working.
#IBAction func valueChanged(_ sender: AnyObject)
{
if(title.text != "")
{
Button.isEnabled = true
}
else
{
Button.isEnabled = false
}
}
Thanks StackedOverflow Community ...
set button's enabled with alpha to make the look better then set enabled/disabled through valueChanged
#IBOulet private weak var myButton: UIButton! {
didSet {
set(myButton, enabled: false)
}
}
#IBAction private func valueChanged(_ sender: UITextView) {
set(myButton, enabled: !sender.text.isEmpty)
}
private func set(_ button: UIButton, enabled: Bool) {
button.isEnabled = enabled
button.alpha = enabled ? 1 : 0.5
}

How to properly end a ARView that uses a Reality Composer project?

My project has a few views before it call a ARview with a reality composer project. I enabled the coaching view in it using the demo code that apple provides. My problem is. If I make a button to go back from that view and call it again, the camera starts to flick from second to second. If I do it again, the flick increases until that, if I do it again, the program crashes. How can I make that view completely new, like the first time I loaded it? I’ve tried removing the anchor from the view.session. Tried pausing the ar session. Could anyone help me with that?
This is my code
import UIKit
import RealityKit
import ARKit
class ARHomeViewController: UIViewController {
#IBOutlet var arView: ARView!
#IBOutlet weak var coachingOverlay: ARCoachingOverlayView!
override func viewDidLoad()
{
super.viewDidLoad()
presentCoachingOverlay()
addScene()
}
/// Begins the coaching process that instructs the user's movement during
/// ARKit's session initialization.
func presentCoachingOverlay() {
coachingOverlay.session = arView.session
coachingOverlay.delegate = self
coachingOverlay.goal = .horizontalPlane
coachingOverlay.activatesAutomatically = false
self.coachingOverlay.setActive(true, animated: true)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Prevent the screen from being dimmed to avoid interuppting the AR experience.
UIApplication.shared.isIdleTimerDisabled = true
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
arView?.session.pause()
}
func addScene()
{
guard let anchor = try? ExperienciaCasa.loadMenu() else { return }
anchor.generateCollisionShapes(recursive: true)
arView.scene.addAnchor(anchor)
}
}

Show and hide window instead of terminating app on close click in cocoa app

I have been trying to show hide window on close(red button) click on the window. I would like to do is hide the window and when a user clicks on my app again it will show again.
Thanks in advance to all the developers who provide an answer. I am new to Cocoa apps. I am iOS developers so I have not much knowledge about cocoa apps.
I tried to hide(:) method and orderOut(:) method too. but not working.
class ViewController : NSViewController, NSWindowDelegates {
override func viewDidAppear() {
self.view.window?.delegate = self
}
func windowShouldClose(_ sender: NSWindow) -> Bool {
//NSApplication.shared.terminate(self)
//NSApp.hide(self)
//self.view.window?.orderOut(sender)
return false
}
}
I want to create a timer app which runs in the background if user click on close it will hide instead of terminating. and when he clicks again from dock menu it will reopen the window.
I'm not much into Mac OS development, but I think you should inherit from NSWindowController like this:
class MyWindowController: NSWindowController, NSWindowDelegate {
func windowShouldClose(_ sender: NSWindow) -> Bool {
NSApp.hide(nil)
return false
}
}
Then you need just open your Main (or whatever name you have) storyboard, choose Window Controller and set your MyWindowController to it:
I tried and it worked for me.
I have found solution. Thanks to #Silvester suggestion to present NSViewController.
On button click event :
#IBAction func onButtonClick(_ sender: VSButton) {
let animator = ReplacePresentationAnimator()
let vc = self.storyboard?.instantiateController(withIdentifier: "identifier") as! yourVC
present(vc, animator: animator)
}
Custom animator class :
class ReplacePresentationAnimator: NSObject, NSViewControllerPresentationAnimator {
func animatePresentation(of viewController: NSViewController, from fromViewController: NSViewController) {
if let window = fromViewController.view.window {
NSAnimationContext.runAnimationGroup({ (context) -> Void in
fromViewController.view.animator().alphaValue = 0
}, completionHandler: { () -> Void in
viewController.view.alphaValue = 0
window.contentViewController = viewController
viewController.view.animator().alphaValue = 1.0
})
}
}
func animateDismissal(of viewController: NSViewController, from fromViewController: NSViewController) {
if let window = viewController.view.window {
NSAnimationContext.runAnimationGroup({ (context) -> Void in
viewController.view.animator().alphaValue = 0
}, completionHandler: { () -> Void in
fromViewController.view.alphaValue = 0
window.contentViewController = fromViewController
fromViewController.view.animator().alphaValue = 1.0
})
}
}
}
This will work perfectly with Silvester MyWindowController. Thank you.

UIPickerView does not update on other ViewController after countdown timer

I have an options ViewController where the user can change the password and a pickerView. Whenever he presses the save button a timer starts and the user gets directed to the main screen through a segue. I want to be able to grey the pickerView out for a certain amount of time (on the options ViewController) as soon as the user presses this save button (it equals a time-based restriction).
My problem now is that anytime the user presses the button and gets directed to the main screen, the pickerview.alpha on the options ViewController (which i set for the grey out effect) will not change / the change is not visible when the user returns in the time period. Also the pickerview.alpha is not changing back on the options ViewController screen when the time period expieres.
So in order to follow my describtion here is my code so far:
import UIKit
class OptionsViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate
#IBOutlet var PickerView: UIPickerView!
var seconds = 20
var timer = Timer()
var isTimerRunning = false
#IBAction func Save_Touched(_ sender: Any) {
if isTimerRunning == false {
runTimer()
}
self.performSegue(withIdentifier: "fromOptionstoMainSegue", sender: self)
}
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(OptionsViewController.updateTimer), userInfo: nil, repeats: true)
self.PickerView.alpha = 0.5
isTimerRunning = true
}
func updateTimer() {
if seconds < 1 {
timer.invalidate()
self.PickerView.alpha = 1.0
} else {
seconds -= 1
print(seconds)
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.PickerView.dataSource = self
self.PickerView.delegate = self
print(isTimerRunning)
}
}
I tried endless options in order to achieve it, but could not make it.
Therefore i am really looking forward to any answer or help!
With kind regards
You can easily disable the pickerView. Either hide it completely:
PickerView.isHidden = true
then unhide it later, or just simply disable it:
PickerView.isUserInteractionEnabled = false
and enable it again after your save is finished. There is no need to grey out the pickerView.
EDIT:
There is nothing wrong with your code for setting the alpha of your picker view. Make sure your outlet is linked to the picker view in the storyboard.

swift mac osx NSButton is not responding until a long press

I am having a weird issue with a button. So I have a NSViewController with many subviews in it. When I click a button, a new NSView with click gestures and buttons is added on top. But I can't press any of them, they don't respond unless a click for 2 seconds and then release. I've tried disabling the gestures of the holder but it didn't work. Any suggestions?
Well, some of the rest of us do. In my case, it's for buttons on a view in a sheet, so "many subviews" isn't likely it. My view controller for the sheet is about 100 lines. Still debugging...
At present the VC is as follows. The snp.makeConstraints calls are for SnapKit (from GitHub)
#objc
class ThreadEditSheetViewController: NSViewController {
/// The container for the graphics view
#IBOutlet var sheetView: NSView!
/// The information packet initialized by the invoking view controller
var info: ThreadEditInfo!
/// API
override func viewDidLoad() {
super.viewDidLoad()
}
/// API
override func viewWillAppear() {
guard let gvc = (try? self.bundleLoader(id: "GraphicsViewController")) as? GraphicsViewController else {
fatalUserAlert(error: AppError.UIConstructionFailure, message: "Can't find GraphicsViewController for ThreadEditSheetViewController")}
let gv = gvc.view
self.view.addSubview(gv)
// Spaces in title text move it left to avoid visual overlap with scroll bar. Don't know how to do it with
// constraints given the scrolling view
let done = makeButton(gvc: gvc, title: "done ", action: #selector(doneEditing(_:)))
done.snp.makeConstraints{ (make) in
make.top.equalTo(gv).offset(-5)
make.right.equalTo(gv).offset(-5)
}
let cancel = makeButton(gvc: gvc, title: "cancel", action: #selector(cancelEditing(_:)))
cancel.snp.makeConstraints{ (make) in
make.top.equalTo(gv).offset(-5)
make.left.equalTo(gv).offset(5)
}
self.view.becomeFirstResponder()
super.viewWillAppear()
return
}
func makeButton(gvc: NSViewController, title: String, action: Selector) -> NSButton {
let button = NSButton(title: title, target: self, action: action)
let gv = gvc.view
gv.addSubview(button)
button.backgroundColor = .clear
button.setButtonType(.momentaryChange)
button.isTransparent = true
return button
}
#objc
func doneEditing(_ sender: Any) {
self.dismissViewController(self)
}
#objc
func cancelEditing(_ sender: Any) {
self.dismissViewController(self)
}
}