I have come up with a taskbar program that is able to shut and close a window. Key code being:
-(void) openWindow{
NSLog(#"Opening Window");
//put infront of all other apps
[NSApp activateIgnoringOtherApps:YES];
//show window
[[_myView window] orderFront:self];
}
-(void) closeWindow{
NSLog(#"Closing Window");
//hide window
[[_myView window] orderOut:self];
}
This is working perfectly.
The only issue is, I now want the program to start off with the window closed but when I set this:
- (void)viewDidLoad {
[super viewDidLoad];
[self closeWindow];
}
Nothing happens and the window stays open?? And before you ask - Yes 'Visible At Launch' is switched off! Haha
If I add a 0.001 second delay in the view did load it works!!
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.001 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self closeWindow];
});
but then there is a horrible flicker...
If there is a viewWillAppear method, try to put your [self closeWindow] in.
Or maybe you try to close the window before she is visible so the code to show window is executed after your call to closeWindow.
Put some breakpoints if needed to see the order of the methods's execution.
Related
I am having a strange problem.I am having a button , and on pressing the button I am doing
the following
- (IBAction)btnPressed:(id)sender {
[ _spinner startAnimating];//where _spinner is a ActivityIndicator
[self showResult];
}
-(void) showResult{
sleep(10);
resultText.text=#"Hi..Sorry.It has been a long wait";
}
But the spinner never starts animating , even though the showResult method gets called
properly. I feel this very strange . When I put [_spinner startAnimating] in the viewDidLoad
it works perfect. Any help is greatly appreciated.
sleep method get called on the main thread causing UI to hang, that's why you aren't able to see the activity indicator
one way to do this:
- (IBAction)actionbuton:(id)sender {
[_activity startAnimating];
[self performSelectorInBackground:#selector(backgroundProcess) withObject:nil];
}
- (void) backgroundProcess{
sleep(4);
[self performSelectorOnMainThread:#selector(processingDone) withObject:nil waitUntilDone:NO];
}
- (void) processingDone{
[_activity stopAnimating];
}
First start your acivity inside button press method.
Then after call your showResult method in timer.
I think that will resolve your problem.
Also remove Sleep from showResult.
I'm having a problem with the enabling/disabling of a UIButton, disabling the button works fine if I don't enable it again later in my code. When I do enable it later on it shows up as though it's disabled (the opacity changes) yet when I press it the attached IBAction function is still called.
The code:
- (void)loadDataFromURL:(NSURL *)URL withLoadIndicator:(UIActivityIndicatorView *)loadIndicator errorName:(NSString *)name sender:(id)sender andCallback:(SEL)selector{
// Start loading indicator, block button so we will have only one call at a time
[loadIndicator startAnimating];
if ([sender isKindOfClass:[UIButton class]]) {
UIButton *button = sender;
[button setEnabled:NO];
}
// Run the data load sequence
self.dispatchQueue = dispatch_queue_create("com.companyname.settingsqueue", 0);
dispatch_async(self.dispatchQueue, ^{
// Downloading JSON and using CoreData to put it into the sqlite database here
});
// After loading is complete stop animating and re-enable the button
dispatch_async(dispatchQueue, ^{
[loadIndicator stopAnimating];
if ([sender isKindOfClass:[UIButton class]]) {
UIButton *button = sender;
button.enabled = YES;
}
});
}
The strange thing is it works perfectly for the loadIndicator. The button I get from the sender parameter in the function does exist (it's not null). When I remove button.enabled = YES; it stays disabled as it should. Is there a way to enable it again after my async code has executed without the button still being enabled during the async execution?
Thanks in advance for helping me.
I found the answer to my problem after extensive searching. Because I wasn't running all my UIView functions on the main thread the UI didn't update even though my function finished. Therefor the button disabled for a really short time and then enabled again, even though my overlaying UIView and UIActivityIndicator were not yet removed from the screen.
I hope this helps someone else with similar issues.
when i click on button which title is click here to enlarge then i want show activity indicator on the first view and remove when load this view.
but i go back then it show activity indicator which is shown in this view.
in first vie .m file i have use this code for action.
-(IBAction)btnSelected:(id)sender{
UIButton *button = (UIButton *)sender;
int whichButton = button.tag;
NSLog(#"Current TAG: %i", whichButton);
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[spinner setCenter:CGPointMake(160,124)];
[self.view addSubview:spinner];
[spinner startAnimating];
if(whichButton==1)
{
[spinner stopAnimating];
first=[[FirstImage alloc]init];
[self.navigationController pushViewController:first animated:YES];
[spinner hidesWhenStopped ];
}}
in above code i have button action in which i call next view. Now i want show/display activity indicator when view upload. In next view i have a image view in which a image i upload i have declare an activity indicator which also not working. How do that?
Toro's suggestion offers a great explanation and solution, but I just wanted to offer up another way of achieving this, as this is how I do it.
As Toro said,
- (void) someFunction
{
[activityIndicator startAnimation];
// do computations ....
[activityIndicator stopAnimation];
}
The above code will not work because you do not give the UI time to update when you include the activityIndicator in your currently running function. So what I and many others do is break it up into a separate thread like so:
- (void) yourMainFunction {
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[NSThread detachNewThreadSelector:#selector(threadStartAnimating) toTarget:self withObject:nil];
//Your computations
[activityIndicator stopAnimating];
}
- (void) threadStartAnimating {
[activityIndicator startAnimating];
}
Good luck!
-Karoly
[self.navigationController pushViewController:first animated:YES];
Generally, when you push a view controller into navigation controller, it will invoke the -(void)viewWillAppear: and -(void)viewDidAppear: methods. You can add activity indicator view inside the viewWillAppear: and call startAnimation of indicator view. You CANNOT invoke startAnimation and stopAnimation at the same time. For example,
- (void)viewWillAppear:(BOOL)animated
{
[aIndicatorView startAnimation];
// do somethings ....
[aIndicatorView stopAnimation];
}
Because the startAnimation and stopAnimation are under the same time, then no animation will show.
But if you invoke startAnimation in -(void)viewWillAppear: and invoke stopAnimation in another message, like followings.
- (void)viewWillAppear:(BOOL)animated
{
[aIndicatorView startAnimation];
// do somethings...
}
- (void)viewDidAppear:(BOOL)animated
{
[aIndicatorView stopAnimation];
}
Because viewWillAppear: and viewDidAppear: are invoked with different event time, the activity indicator view will work well.
Or, you can do something like followings:
- (void)viewWillAppear:(BOOL)animated
{
[aIndicatorView startAnimation];
// Let run loop has chances to animations, others events in run loop queue, and ... etc.
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]];
// do somethings ....
[aIndicatorView stopAnimation];
}
The above example is a bad example, because it invokes two or more animations in the -runUntilDate:. But it will let the activity indicator view work.
Create a webview. Add a activity indicator to the webview. If you are loading a image via url into the webview then implement the webview delegate methods. Once the url is loaded then stopanimating the activity indicator.
Let me know which step you are not able to implement.
I have a custom NSWindow subclass that the user can toggle the display of with the click of a button. I'd also like the window to disappear when the window resigns key status (e.g. by the user clicking outside the window).
I have a delegate that implements windowDidResignKey: but I find that this delegate method is only invoked the first time the window resigns key.
Here's how I toggle the display of the window (via user action or windowDidResignKey):
- (void) toggleWindowAtPoint:(NSPoint)point
{
// Attach/detach window.
if (!attachedWindow)
{
attachedWindow = [[CustomWindow alloc] attachedToPoint:point];
attachedWindow.delegate = self;
[attachedWindow setLevel:NSMainMenuWindowLevel+1]; // show window in front of all other apps on desktop
[attachedWindow makeKeyAndOrderFront:self];
}
else
{
attachedWindow.delegate = nil;
[attachedWindow orderOut:self];
[attachedWindow release];
attachedWindow = nil;
}
}
Here's my implementation of windowDidResignKey:
- (void) windowDidResignKey:(NSNotification *)note
{
[self toggleWindowAtPoint:NSMakePoint(0, 0)];
}
I'm finding that the first time the custom window is displayed, windowDidResignKey: gets called. Every time the custom window is re-displayed after that, windowDidResignKey: is not getting invoked.
The issue was that in some cases, the custom window was not actually becoming the key window after calling [attachedWindow makeKeyAndOrderFront:self].
I fixed this by adding the following line before re-creating the window:
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
In the context of the code snippet above:
- (void) toggleWindowAtPoint:(NSPoint)point
{
// Attach/detach window.
if (!attachedWindow)
{
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
attachedWindow = [[CustomWindow alloc] attachedToPoint:point];
....
Have you tried calling [attachedWindow makeFirstResponder:attachedWindow] in your toggle method?
If you want to activate a window without using activateIgnoringOtherApps: you should use a NSPanel with a NSNonactivatingPanelMask:
[[CustomPanel alloc]
initWithContentRect: NSZeroRect
styleMask: NSNonactivatingPanelMask
backing: NSBackingStoreBuffered
defer: NO];
I have a view which contains two views. One of those views contains two buttons and some text labels. The other one, with alpha set to 0.25, has an UIActivityIndicatorView to tell the user that the app is working and he must wait until it finishes. If the user touch a button while the UIActivityIndicatorView is spinning, when the UIActivityIndicatorView stops, the app remember the user action and responds to it. How can I discard the user interaction that occur while the UIActivityIndicatorView is spinning?
Thanks for reading.
P.D.: Like is commented in this thread, I prefer do not to use any modal solution.
EDITED:
I am currently using this code and it does not work right.
- (void)viewDidAppear:(BOOL)animated {
// The view appears with an UIActivityIndicatorView spinning.
[self showResults]; // The method that takes a long time to finish.
[self.activityIndicator stopAnimating];
// When the showResults method ends, the view shows the buttons to the user.
[self.activityIndicatorView setHidden:YES];
[self.menuButton setEnabled:YES];
[self.menuButton setUserInteractionEnabled:YES];
[self.playButton setEnabled:YES];
[self.playButton setUserInteractionEnabled:YES];
[self.view setUserInteractionEnabled:YES];
[self.interactionView setUserInteractionEnabled:YES];
}
I found these methods very useful:
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
In Swift 3.0
To Disable interaction :-
UIApplication.shared.beginIgnoringInteractionEvents()
To restore interaction :-
UIApplication.shared.endIgnoringInteractionEvents()
[_button setUserInteractionEnabled:NO];
That should disable it, just set YES for when you want to user to tap it.
BOOL i_am_ready_to_submit = NO;
-(void)action_finished{
[self.activityIndicator stopAnimating];
i_am_ready_to_submit = YES;
}
-(IBAction)submit_button{
if(i_am_ready_to_submit){
[self submit];
}
}
just add
[self.view setUserInteractionEnabled:NO];
before the
[self.activityIndicator startAnimating];
and reenable it after
[self.activityIndicator stopAnimating];
[self.view setUserInteractionEnabled:YES];
To disable touch event in a view,
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
To enable touch event in a view
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
For swift 5 you can use:
self.view.isUserInteractionEnabled = false
and to enable all again:
self.view.isUserInteractionEnabled = true
If you have some lag problem, like freeze for about a couple of seconds just put this in:
DispatchQueue.main.async{}
You could disable/enable the UIButtons based on the UIActivityIndicatorView being shown or not. Or, if you just want to "discard the user interaction" while the spinner is shown, in the button handler method:
- (void)buttonTapped:(id)sender {
if ([spinner superview] != nil && [spinner isAnimating]) {
return;
}
// ... the rest of your code
}
This example assumes that when you hide the UIActivityIndicatorView you call one of:
[spinner removeFromSuperview];
or
[spinner stopAnimating];
Use SVProgressHUD WrapperClass It have so many options to show ActivityIndicator
For Source Code Click Here !
[SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeBlack];
use above statement to disable background touches
[SVProgressHUD dismiss]
To enable background touches.
#IBAction func yourButtonPressed(sender: UIButton) {
if self.activityIndicator.isAnimating() {
//remember the action user asked of you using the sender
} else {
//do your stuff
return
}
yourButtonPressed(yourButton)
}
or you code use
self.activityIndicator.animationDidStop to determine when to run your stuff
A quick solution: add a transparent or pseudo transparent view that cover the whole screen. Add your activity indicator on top of this view. When the wait period finishes, remove both views. Get some inspiration.
A better solution, because you can't hide the whole screen in all situations, is to manage the state of the app (ignore actions when the app is 'busy') and disable/enable the appropriate buttons and other controls depending on each app state.
Though answer is replied in earlier response, just like to add for information purpose "[self.activityIndicatorView setHidden:YES];" no need to call this method explicitly, because startAnimating/stopAnimating already take care of this. I'm assuming you are using default value of "hidesWhenStopped" property.