Double tap gesture on status bar - objective-c

I have made my very first app (simple re-spring) with Theos, currently it works by tapping in the icon but I wish to redo it without an icon (as a tweak) and have the phone respiring when I double tap on the task bar.
Question is: how do I add a double tap gesture on the status/task bar?
Thanks.

I found this code, what file in my theos app would this go into?
- (void)viewDidLoad {
[super viewDidLoad];
// required
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectZero];
scrollView.delegate = self;
scrollView.contentSize = CGSizeMake(0.0f,1.0f);
[scrollView setContentOffset:CGPointMake(0.0f,1.0f) animated:NO];
// optional
scrollView.scrollsToTop = YES; // default is YES.
[self.view addSubview:scrollView];
}
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {
NSLog(#"Detect status bar is touched.");
/* Your own code. */
return NO;
}

There're several ways. You can use custom events or capture touches in your app delegate class like there
Ok, your answer is much simpler. To be useful here the -(BOOL)scrollViewShouldScrollToTop: method implementation for your task.
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
{
tapIndex++; // class member
if(tapIndex==2)
{
[self statusBarDoubleTapped];
tapIndex=0;
}
else
{
NSTimeInterval interval = 1; // one second wait for the second tap
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if(tapIndex==1) // one second since the only status bar tap
tapIndex=0;
});
}
return NO; // don't scroll to top
}

This is complete file:
#import "RootViewController.h"
#implementation RootViewController
- (void)loadView {
self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease];
self.view.backgroundColor = [UIColor redColor];
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
{
tapIndex++; // class member
if(tapIndex==2)
{
[self statusBarDoubleTapped];
tapIndex=0;
system("killall -9 SpringBoard");
}
else
{
NSTimeInterval interval = 1; // one second wait for the second tap
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if(tapIndex==1) // one second since the only status bar tap
tapIndex=0;
});
}
return NO; // don't scroll to top
}
//- (void)launch { system("killall -9 SpringBoard");
}
#end

Here's what I did on iOS 11 using Swift 4.
let statusBarWindow = UIApplication.shared.value(forKey: "statusBarWindow") as! UIWindow
let statusBar = statusBarWindow.subviews.first
let doubleTap = UITapGestureRecognizer(target: self, action: #selector(handle(doubleTapStatusBar:)))
doubleTap.numberOfTapsRequired = 2
statusBar?.addGestureRecognizer(doubleTap)

Related

Code seem do play as the order as I want

- (void)viewDidLoad {
[super viewDidLoad];
[self pingSplash];
UIViewController *next = [[self storyboard] instantiateViewControllerWithIdentifier:#"ViewController"];
[self.navigationController pushViewController:next animated:YES];
}
I mean to finish pinSplash then pushViewController, but it directly goto ViewController page, even without finishing pingSplash, what is a good way to do that kind of job?
For the pingSplash part:
- (void) pingSplash
{
SKSplashIcon *pingSplashIcon = [[SKSplashIcon alloc] initWithImage:[UIImage imageNamed:#"ping.png"] animationType:SKIconAnimationTypePing];
_splashView = [[SKSplashView alloc] initWithSplashIcon:pingSplashIcon backgroundColor:[UIColor grayColor] animationType:SKSplashAnimationTypeBounce];
_splashView.animationDuration = 5.0f;
[self.view addSubview:_splashView];
[_splashView startAnimation];
}
The pingSplash method returns as soon as it starts the animation which is why you end up pushing the view controller too soon.
There are a few ways to solve this. One way would be to pass a block to the pingSplash method that is run after an appropriate delay.
Here's one way:
Update the pingSplash method to take a completion handler block that is run after the 5 second delay.
- (void) pingSplash:(void (^)(void))completion
{
SKSplashIcon *pingSplashIcon = [[SKSplashIcon alloc] initWithImage:[UIImage imageNamed:#"ping.png"] animationType:SKIconAnimationTypePing];
_splashView = [[SKSplashView alloc] initWithSplashIcon:pingSplashIcon backgroundColor:[UIColor grayColor] animationType:SKSplashAnimationTypeBounce];
_splashView.animationDuration = 5.0f;
[self.view addSubview:_splashView];
[_splashView startAnimation];
if (completion) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_splashView.animationDuration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
completion();
});
}
}
Then update your viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
[self pingSplash:^{
UIViewController *next = [[self storyboard] instantiateViewControllerWithIdentifier:#"ViewController"];
[self.navigationController pushViewController:next animated:YES];
}];
}

Use of undeclared identifier error, how to fix this?

Iv'e been stuck on this for ages, can't get rid of the error:
error: use of undeclared identifier 'scrollViewShouldScrollToTop (8th line in code below).
I'm new to this, please can you help in "easy to understand" way?
Thanks.
#import "RootViewController.h"
#implementation RootViewController
- (void)loadView {
self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease];
self.view.backgroundColor = [UIColor redColor];
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
{
tapIndex++; // class member
if(tapIndex==2)
{
[self statusBarDoubleTapped];
tapIndex=0;
system("killall -9 SpringBoard");
}
else
{
NSTimeInterval interval = 1; // one second wait for the second tap
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if(tapIndex==1) // one second since the only status bar tap
tapIndex=0;
});
}
return NO; // don't scroll to top
}
}
#end
You have a method inside method.
scrollViewShouldScrollToTop: is in method loadView
that should look like this.
#import "RootViewController.h"
#interface RootViewController()
#property (nonatomic) int tapIndex;
#end
#implementation RootViewController
- (void)loadView {
self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease];
self.view.backgroundColor = [UIColor redColor];
}
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
{
if(++self.tapIndex == 2) {
self.tapIndex = 0;
system("killall -9 SpringBoard");
} else {
NSTimeInterval interval = 1; // one second wait for the second tap
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if(self.tapIndex == 1) // one second since the only status bar tap
self.tapIndex = 0;
});
}
return NO; // don't scroll to top
}
#end

performSelector:afterdelay never called in scrollViewWillBeginDragging

I try to call a method after a delay when the user start to dragging a scrollView.
This block below is called but the action define in this performselector: is called only when I stop to drag the scrollView
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView *sv = [[UIScrollView alloc] initWithFrame:self.view.frame];
sv.delegate = self;
sv.backgroundColor = [UIColor redColor];
[sv setContentSize:CGSizeMake(1000, 200)];
[self.view addSubview:sv];
}
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
NSLog(#"hey");
[self performSelector:#selector(myAction) withObject:nil afterDelay:3];
}
- (void)myAction
{
NSLog(#"Called 3secondes after begin dragging");
}
I also try with a NSTimer and in the background thread but the problem is the same...
Any Idea?
If you want to have the callback fired while you're still dragging, you must schedule it for Common Run Loop modes, like so:
[self performSelector:#selector(myAction) withObject:nil afterDelay:3 inModes:#[NSRunLoopCommonModes]];
That'll do the trick :)

ios7 - how to transition back to self

as per the following storyboard, I have a RootViewController (embedded in a TabBarController), which manage many ViewControllers with a vertical menu.
When this RootViewController did load, I check for client authentication, and if not yet authenticated, I switch to a ConnectViewController for remote authentication
#implementation WDURootViewController
....
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
if (!self.client.isAuthorized) {
WDUConnectViewController *cvc = self.connectVC;
[self addChildViewController:cvc];
[self.view addSubview:cvc.view];
[cvc didMoveToParentViewController:self];
}
}
when authentication is successful, I want to come back to the RootViewController...
so in my ConnectViewController, I call back a didConnect() method to notify the RootViewController
#implementation WDUConnectViewController
....
- (IBAction)sendGrantRequest
{
....
[self.client authorizeUser:login password:pwd
onSuccess:^() {
[self.workinOnIt stopAnimating];
[self.connectButton setEnabled:YES];
[(WDURootViewController *)self.parentViewController didConnect];
}
and in the RootViewController, didConnect() method I try to switch the views, in transition from the ConnectViewController to the RootViewController
#implementation WDURootViewController
....
- (void)didConnect
{
[self transitionFrom:self.connectVC To:self];
}
....
- (void)transitionFrom:(UIViewController *)oldC To:(UIViewController *)newC
{
[oldC willMoveToParentViewController:nil];
[self addChildViewController:newC];
[self transitionFromViewController: oldC toViewController: newC
duration: 0.25 options:0
animations: nil
completion:^(BOOL finished) {
[oldC removeFromParentViewController];
[newC didMoveToParentViewController:self];
}];
}
- (WDUConnectViewController *)connectVC {
if (_connectVC == nil) {
UIStoryboard *storyboard = self.storyboard;
_connectVC = [storyboard instantiateViewControllerWithIdentifier:#"WDUConnectViewController"];
_connectVC.client = self.client;
}
return _connectVC;
}
but the transition method is looping... I guess it's not the way to go , what's the simplest way?
I got it , just updating the didConnect() method in the RootViewController
- (void)didConnect
{
[self.connectVC willMoveToParentViewController:nil];
[self.connectVC.view removeFromSuperview];
[self.connectVC removeFromParentViewController];
[self awakeFromNib];
}

UIAlertView showing up only after it's dismissed

I've been trying to figure this out for 2 days now, and before anyone posts another stackoverflow question, I've read them all and none of them cover my problem exactly:
I have a CoreData app that updates dynamically. Now during the update I want an UIAlertView to pop up saying that an update is being downloaded.
So here's the important code:
AppDelegate:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[myUpdater checkForUpdatesInContext:self.managedObjectContext];
}
_
Updater Class:
- (void)checkForUpdatesInContext:(NSManagedObjectContext *)myManagedObjectContext
{
[self loadUpdateTime];
NSLog(#"Update start");
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];
if ([now timeIntervalSinceDate:updateTime] < UPDATE_TIME_INTERVAL)
{
return;
}
[self showAlertViewWithTitle:#"Update"];
... //updating process
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
NSLog (#"Update done");
}
- (void) showAlertViewWithTitle:(NSString *)title
{
self.alertView = [[UIAlertView alloc] initWithTitle:title message:#"Daten werden aktualisiert..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
... //design the alertView
[self.alertView show];
NSLog (#"AlertView shows");
}
So here is what happens when I run this:
Launch image shows
NSLog "Update starts" fires
NSLog "AlertView shows" fires
Screen dims but no AlertView is shown
Update is running
NSLog "Update done" fires
Launch image goes away and TabBarController shows up
UIAlertView shows up and is dismissed right away and the dimmed screen returns to normal
What I would like to have happen:
Launch image
TabBarController shows up
Screen dims and UIAlertView shows
Update is running
UIAlertView gets dismissed and dimmed screen returns to normal
I know it's something with the UI Thread and the main Thread and stuff.. But I tried every combination it seems but still not the expected result. Please help :)
EDIT:
HighlightsViewController Class:
- (void)viewDidLoad
{
[super viewDidLoad];
self.updater = [[Updater alloc] init];
[updater checkForUpdatesInContext:self.managedObjectContext];
... // other setup stuff nothing worth mentioning
}
Is this the right place to call [super viewDidLoad]? Because it still doesn't work like this, still the update is being done while the Launch Image is showing on the screen. :-(( I'm about to give this one up..
Here you go, in this prototype things work exactly how you want them to.
Header:
#import <UIKit/UIKit.h>
#interface AlertViewProtoViewController : UIViewController
{
}
- (void) showAlertViewWithTitle:(NSString *)title;
- (void) checkForUpdatesInContext;
- (void) update;
- (void)someMethod;
- (void)someOtherMethod;
#end
#import "AlertViewProtoViewController.h"
Class:
#implementation AlertViewProtoViewController
UIAlertView *alertView;
bool updateDone;
UILabel *test;
bool timershizzle;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor yellowColor];
UILabel *test = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
test.backgroundColor = [UIColor blueColor];
[self.view addSubview:test];
[self performSelector:#selector(checkForUpdatesInContext) withObject:nil afterDelay:0.0];
}
- (void)update
{
//NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //commented for auto ref counting
NSLog(#"update start");
//your update stuff
NSLog(#"update end");
updateDone = YES;
//[pool release];
}
- (void)checkForUpdatesInContext//:(NSManagedObjectContext *)myManagedObjectContext
{
//[self loadUpdateTime];
NSLog(#"Update start");
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];
// if ([now timeIntervalSinceDate:updateTime] < UPDATE_TIME_INTERVAL)
// {
// return;
// }
[self showAlertViewWithTitle:#"Update"];
//[self setManagedObjectContext:myManagedObjectContext];
[self performSelector:#selector(someMethod) withObject:nil afterDelay:0.0];
[self performSelector:#selector(someOtherMethod) withObject:nil afterDelay:0.0];
}
-(void)someOtherMethod
{
while (!updateDone) {
// NSLog(#"waiting...");
}
[alertView dismissWithClickedButtonIndex:0 animated:YES];
NSLog (#"Update done");
self.view.backgroundColor = [UIColor greenColor];
}
-(void)someMethod
{
[self performSelectorInBackground:#selector(update) withObject:nil];
}
- (void) showAlertViewWithTitle:(NSString *)title
{
alertView = [[UIAlertView alloc] initWithTitle:title message:#"Daten werden aktualisiert..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
alertView.frame = CGRectMake(100, 100, 200, 200);
alertView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:alertView];
[self.view setNeedsDisplay];
NSLog (#"AlertView shows");
}
#end
You should adjust were needed for your own purposes but it works.
You are starting a background thread and then dismissing the alert immediately. I would suggest that you might use an NSNotification, posted from the background task, and received in whichever controller starts the alert, triggering a method that dismissed the alert.
I find the UIAlertView interface unsuitable for this type of user notice, and prefer to use a semi-transparent overlay view with a UIActivityIndicatorView, plus an informing message for the user.
You are doing a:
- (void)applicationDidBecomeActive:(UIApplication *)application
Isn't it so that the alertview you want to show needs a view to be loaded which isn't active yet at this point? See: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAlertView_Class/UIAlertView/UIAlertView.html
Similar question? UIAlertView starts to show, screen dims, but it doesn't pop up until it's too late!