Cocos2d Xcode - SLComposeViewController Black Screen - ios

I've got a Cocos2d game that I've been working on, and I've managed to get it to present an SLComposeViewController by creating a button on screen like this:
The header file looks like this:
#interface HighScores : Main
#end
#interface socialViewControllerAtTheBottomOfThisClass : UIViewController
#end
The code inside the .m file:
#implementation HighScores
- (init) {
UIButton *shareButton = [[UIButton alloc] initWithFrame:CGRectMake(screenWidth/2, screenHeight/2, 100, 30)];
[shareButton addTarget:self action:#selector(shareAction) forControlEvents:UIControlEventTouchUpInside];
}
- (void)shareAction {
// I created a ViewController class at the end of the .m file containing the social stuff
// but I did this and managed to get it to present the SLComposeViewController:
socialViewControllerAtTheBottomOfThisClass *bottomController = [[socialViewControllerAtTheBottomOfThisClass alloc] init];
[[[[CCDirector sharedDirector] openGLView] window] setRootViewController:bottomController];
[bottomController shareToFacebook];
}
}
#end
Then at the bottom for the ViewController implementation:
#implementation socialViewControllerAtTheBottomOfThisClass
- (void)shareToFacebook {
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
SLComposeViewController *controller = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[controller setInitialText:#"This is my facebook status!"];
[self presentViewController:controller animated:YES completion:nil];
controller.completionHandler = ^(SLComposeViewControllerResult result) {
switch(result) {
case SLComposeViewControllerResultCancelled: [self actionForCancelled];
break;
case SLComposeViewControllerResultDone: [self actionForDone];
break;
}};
}
}
- (void)actionForCancelled {
}
- (void)actionForDone {
}
#end
The code presents the SLComposeViewController, but while presenting, I get a black background and after I tap either Post or Cancel, the screen stays black. I was thinking of setting the rootViewController as HighScores, but seeing as it's not a ViewController, I'm not able to do that.

I don't have the code where I am at now, but I believe in the past I created the SLComposeViewController and added it as a subview similar to:
[[[CCDirector sharedDirector] openGLView] addSubView:controller.view];
And to remove it you'll have to remove the subview. You can also try:
AppController* app = (AppController*) [[UIApplication sharedApplication] delegate];
[[app navController] presentModalViewController:controller animated:YES];

Related

MPMediaPicker does not show

In a sample app that I'm making for Apple, I cannot get the MPMediaPickerController to show.
I've already added the NSAppleMusicUsageDescription key in the info.plist file, and this is what makes my post different from any other answers found online.
I've also tried adding CoreMedia.framework.
I'm using XCode 10 beta 4
The app never asks for permissions to access the media library, and when I present the picker, the mediaPickerDidCancel method is called right away.
What am I doing wrong?
Thanks for any help!
Header file:
#import <UIKit/UIKit.h>
#import <MediaPlayer/MPMediaPickerController.h>
#interface ViewController : UIViewController<MPMediaPickerControllerDelegate>
#end
Objc file:
#import "ViewController.h"
#import <MediaPlayer/MediaPlayer.h>
#interface ViewController ()
#end
#implementation ViewController {
MPMediaPickerController *picker;
}
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)selectButtonPressed:(id)sender {
picker = [[MPMediaPickerController alloc] initWithMediaTypes: MPMediaTypeAnyAudio];
[picker setDelegate: self];
[picker setAllowsPickingMultipleItems: NO];
picker.prompt = #"Select a Song.";
UIViewController *rootController = [UIApplication sharedApplication].keyWindow.rootViewController;
[rootController presentViewController:picker animated:YES completion:^{
NSLog(#"Complete!");
}];
}
- (void) mediaPicker: (MPMediaPickerController *) mediaPicker didPickMediaItems: (MPMediaItemCollection *) collection {
MPMediaItem *firstItem;
for (MPMediaItem *item in collection.items) {
firstItem = item;
break;
}
MPMusicPlayerController *samplePlayer = [MPMusicPlayerController applicationMusicPlayer];
[samplePlayer setShuffleMode: MPMusicShuffleModeOff];
[samplePlayer setRepeatMode: MPMusicRepeatModeOne];
[samplePlayer beginGeneratingPlaybackNotifications];
// self.mediaItem chosen using MPMediaPickerController
[samplePlayer setQueueWithItemCollection:[[MPMediaItemCollection alloc] initWithItems:#[firstItem]]];
[samplePlayer prepareToPlay];
// Assume that song is at least 120 seconds long
[samplePlayer play];
}
#pragma mark - delegate methods and segues
- (void) mediaPickerDidCancel: (MPMediaPickerController *) mediaPicker {
[self dismissViewControllerAnimated:true completion:^{
}];
}
#end

How to go one view controller to another view controller when we login with social networks in ios

Hi i am new for Ios and in my app i am trying to move one view controller to another view controller when we login with social networks as like twitter for this i have already registered my app with twitter
According to my code when we tapped on twitter login button then twitter login page will be loaded on screen and there is "AuthorizedApp" button is available on twitter login page when we click on that button we get user details
After we get that user details i want move another page
Note:-
My main intention is when we clicked on that "AuthorizedApp" button then i want to move another page please help me some one
According to my code i am getting exception like:- Warning: Attempt to present on whose view is not in the window hierarchy!
My code:-
#import "ViewController.h"
#import "FHSTwitterEngine.h"
#import "ViewController1.h"
#import "AppDelegate.h"
#interface ViewController ()<FHSTwitterEngineAccessTokenDelegate>
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[FHSTwitterEngine sharedEngine]permanentlySetConsumerKey:#"XXXXXXXXXXXXXX" andSecret:#"XXXXXXXXXXXXXXXXXXXXXXXXXX"];
[[FHSTwitterEngine sharedEngine]setDelegate:self];
[[FHSTwitterEngine sharedEngine]loadAccessToken];
//google plus login button
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self
action:#selector(loginOAuth)
forControlEvents:UIControlEventTouchUpInside];
// [button setImage:[UIImage imageNamed:#"twitter-icon.png"] forState:UIControlStateNormal];
button.frame = CGRectMake(10, 390, 300, 30);
button.backgroundColor = [UIColor redColor];
CALayer * d = [button layer];
[d setMasksToBounds:YES];
[d setCornerRadius:20];
[self.view addSubview:button];
}
- (void)loginOAuth {
UIViewController *loginController = [[FHSTwitterEngine sharedEngine]loginControllerWithCompletionHandler:^(BOOL success) {
NSLog(success?#"L0L success":#"O noes!!! Loggen failure!!!");
NSLog(#"User name ---->>>%#",FHSTwitterEngine.sharedEngine.authenticatedUsername);
NSLog(#"User id ------> %#",FHSTwitterEngine.sharedEngine.authenticatedID);
[self movetoanotherview];
}];
[self presentViewController:loginController animated:YES completion:nil];
}
-(void) movetoanotherview{
ViewController1 *dvc = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController1"];
[dvc setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentViewController:dvc animated:YES completion:nil];
}
I think this is happening because you're creating a view controller in a block. The view controller will be gone together with the block at the end of it's scope.
Try to declare dvc as a property inside your .h file (or at the top of your .m file)
#property (strong, nonatomic) ViewController1 *dvc;
Then do this instead:
self.dvc = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController1"];
[_dvc setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentViewController:_dvc animated:YES completion:nil];

SMS View Controller does not dismiss itself

So I have a view controller from which I have an action method sendSMS, which creates the SMS View Controller... Problem is, when I actually send the message, the controller will not dismiss, or it won't create any logs, so I guess the didFinishWithResult method is not even called. Big thanks goes to all of you!
So, my .m looks like this:
- (void)presentViewController:(UIViewController *)controller animated:(BOOL)animated onComplete:(void (^)(void))callback
{
MIKEAppDelegate *APP_DELEGATE = [UIApplication sharedApplication].delegate;
UIViewController *presentedModalVC = [APP_DELEGATE.window.rootViewController presentedViewController];
if (presentedModalVC) {
while (presentedModalVC.presentedViewController) {
presentedModalVC = presentedModalVC.presentedViewController;
}
[presentedModalVC presentViewController:controller animated:animated completion:callback];
} else {
[APP_DELEGATE.window.rootViewController presentViewController:controller animated:animated completion:callback];
}
}
-(void)sendSMS
{
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
if([MFMessageComposeViewController canSendText])
{
NSLog(#"SMS composer appeared");
controller.body = #"Testy Test";
controller.recipients = [NSArray arrayWithObjects:#"774252704", nil];
controller.messageComposeDelegate = self;
[controller presentViewController:controller animated:YES onComplete:nil];
}
}
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller
didFinishWithResult:(MessageComposeResult)result
{
// Notifies users about errors associated with the interface
switch (result)
{
case MessageComposeResultCancelled:
NSLog(#"Result: SMS sending canceled");
break;
case MessageComposeResultSent:
NSLog(#"Result: SMS sent");
break;
case MessageComposeResultFailed:
NSLog(#"Result: SMS sending failed");
break;
default:
NSLog(#"Result: SMS not sent");
break;
}
[self dismissViewControllerAnimated:YES completion:NULL];
}
EDIT 1:
My .h looks like this:
#import <UIKit/UIKit.h>
#import <MessageUI/MFMessageComposeViewController.h>
#interface MIKETableViewController : UIViewController
<UITableViewDataSource, UITableViewDelegate, MFMessageComposeViewControllerDelegate>
-(void)viewWillAppear:(BOOL)animated;
-(void) sendSMS;
#end
EDIT 2:
Ok I tried to launch sendSMS method by pressing button, and everything works as it should, so there is a problem in that HOW I call the method. Thing is that I call the method from myCustomTableCell Class... Idea is, when I slide the cell of the screen It will call the sendSMS method. Please see .m file from my custom cell
-(void)panGestureRecognizer:(UIPanGestureRecognizer *)sender{
CGPoint translation = [sender translationInView:self];
MIKETableViewController *mainController = [[MIKETableViewController alloc] init];
//NSLog(#"Panned with translation point: %#", NSStringFromCGPoint(translation));
sender.view.center = CGPointMake(sender.view.center.x + translation.x,
sender.view.center.y);
CGPoint breakingPoint = CGPointMake(320,sender.view.center.y);
CGPoint startPoint = CGPointMake(150, sender.view.center.y);
CGPoint endPoint = CGPointMake(500, sender.view.center.y);
if (sender.view.center.x <= startPoint.x) {
sender.view.center = startPoint;
}
if (sender.state == UIGestureRecognizerStateEnded) {
if (sender.view.center.x >= breakingPoint.x) {
[UIView animateWithDuration:0.2
delay:0.0
options: UIViewAnimationOptionCurveEaseOut
animations:^{
sender.view.center = endPoint;
}
completion:^(BOOL finished){
NSLog(#"Bought!");
self.timeLabel.text = timeLabelValue;
self.priceLabel.text = priceLabelValue;
self.infoLabel.text = infoLabelValue;
[mainController tableView:mainController.self.tableView didSelectRowAtIndexPath:mainController.self.tableView.indexPathForSelectedRow];
[mainController sendSMS];
}];
} else {
//recognizer.view.center = startPoint;
[UIView animateWithDuration:0.2
delay:0.0
options: UIViewAnimationOptionCurveEaseOut
animations:^{
sender.view.center = startPoint;
}
completion:^(BOOL finished){
NSLog(#"Returned!");
}];
}
}
[sender setTranslation: CGPointZero inView: self];
}
You are dismissing self in the mail composer delegate method, instead of the mail view controller, change:
[self dismissViewControllerAnimated:YES completion:NULL];
to
[controller dismissViewControllerAnimated:YES completion:NULL];
It should work, But your code looks proper, so most probably you have not conformed the delegate <MFMessageComposeViewControllerDelegate>
#Janak Nirmal : Sorry, In hurry i didn't see the delegate method implementation.
Put the break point in the delegate method and see whether the control comes to that method.
In sendSMS method use this code to present :
[self presentViewController:controller animated:YES completion:nil];
now check. and only when send or cancel button pressed, the delegate will be called.
EDIT
The problem is because of that method :
presentViewController:animated:onComplete:
On which controller you present from the same controller you need to dismiss.
For example :
[self presentViewController:viewController animated:YES onComplete:nil];
[self dismissViewControllerAnimated:YES completion:nil];
or
[[UIApplication sharedApplication].delegate.window.rootViewController presentViewController:controller animated:animated completion:callback];
[[UIApplication sharedApplication].delegate.window.rootViewController
dismissViewControllerAnimated:YES completion:nil];
EDIT
Import this in your .h file
#import <MessageUI/MessageUI.h>
Add this header file and check whether the delegate is being called.
EDIT
So you are saying that :
messageComposeViewController:didFinishWithResult:
this delegate method even now is not getting called on clicking send or cancel????
EDIT
instead of this line of code
[controller presentViewController:controller animated:YES onComplete:nil];
put this code and tell me whether the delegate method being called
UIViewController *rootViewController = [[[[UIApplication sharedApplication] delegate] window]rootViewController];
[rootViewController presentViewController:viewController animated:YES completion:nil];
EDIT
Only way is left out is, give me access to your code somewhere in VCS and i will help you out with the problem.

How do I present a UIViewController from SKScene?

I'm entering iOS via Sprite Kit, which I recognize is unwise.
My goal is to display a "Share" button upon Game Over. Tapping the share button should present a SLComposeViewController (Twitter Share). The contents of the scene should not change.
The game logic that dictates "Game Over" lives in SpriteMyScene.m, a subclass of SKScene.
I'm able to display a Share button on Game Over this way:
-(void)update:(CFTimeInterval)currentTime {
if (gameOver){
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(sendToController)
forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Show View" forState:UIControlStateNormal];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[self.view addSubview:button];
}
}
- (void)sendToController
{
NSLog(#"ok");
SpriteViewController *viewController = [SpriteViewController alloc];
[viewController openTweetSheet];
}
Where I get stuck is trying to get the showTweetButton method to work. My SpriteViewController.m looks like this:
- (void)openTweetSheet
{
SLComposeViewController *tweetSheet = [SLComposeViewController
composeViewControllerForServiceType:
SLServiceTypeTwitter];
// Sets the completion handler. Note that we don't know which thread the
// block will be called on, so we need to ensure that any required UI
// updates occur on the main queue
tweetSheet.completionHandler = ^(SLComposeViewControllerResult result) {
switch(result) {
// This means the user cancelled without sending the Tweet
case SLComposeViewControllerResultCancelled:
break;
// This means the user hit 'Send'
case SLComposeViewControllerResultDone:
break;
}
};
// Set the initial body of the Tweet
[tweetSheet setInitialText:#"just setting up my twttr"];
// Adds an image to the Tweet. For demo purposes, assume we have an
// image named 'larry.png' that we wish to attach
if (![tweetSheet addImage:[UIImage imageNamed:#"larry.png"]]) {
NSLog(#"Unable to add the image!");
}
// Add an URL to the Tweet. You can add multiple URLs.
if (![tweetSheet addURL:[NSURL URLWithString:#"http://twitter.com/"]]){
NSLog(#"Unable to add the URL!");
}
// Presents the Tweet Sheet to the user
[self presentViewController:tweetSheet animated:NO completion:^{
NSLog(#"Tweet sheet has been presented.");
}];
}
I always get something like this in the logs:
-[UIView presentScene:]: unrecognized selector sent to instance 0x13e63d00 2013-10-17 18:40:01.611 Fix[33409:a0b] * Terminating app
due to uncaught exception 'NSInvalidArgumentException', reason:
'-[UIView presentScene:]: unrecognized selector sent to instance
0x13e63d00'
You're creating a new view controller but never presenting it:
SpriteViewController *viewController = [SpriteViewController alloc];
I'm assuming that SpriteViewController is what presents your SpriteMyScene, and you'd like to hand control back to the presenting SpriteViewController.
You need to keep a reference to SpriteViewController in your SpriteMyScene subclass, and then access that reference when you call openTweetSheet.
in SpriteMyScene.h
#class SpriteViewController;
#interface SpriteMyScene : SKScene
#property (nonatomic, weak) SpriteViewController *spriteViewController;
#end
in SpriteViewController.m
// somewhere you initialize your SpriteMyScene object, I'm going to call it myScene
myScene.spriteViewController = self;
in SpriteMyScene.m
#import "SpriteViewController.h"
- (void)sendToController
{
NSLog(#"ok");
// use the already-created spriteViewController
[_spriteViewController openTweetSheet];
}
You can use
UIViewController *vc = self.view.window.rootViewController;
This code will give you the access to your root View controller so you can do anything you do will your view controller like normal.
However, do you need to add a button? Use a sprite and add an event to it is better for you in this case. Just call:
UIViewController *vc = self.view.window.rootViewController;
[vc openTweetSheet];
And
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
NSArray *nodes = [self nodesAtPoint:[touch locationInNode:self]];
for (SKNode *node in nodes) {
if ([node.name isEqualToString:#"OpenTweet"]) {
UIViewController *vc = self.view.window.rootViewController;
[vc openTweetSheet];
}
}
}
If you want to open another UIViewController from inside your scene, you have to first create a delegate in the primary View Controller that originally created this scene so your scene can notify its ViewController of an open tweet action. You will need following steps:
Define a delegate in the primary View Controller - the view controller of our scene, to handle the open tweet action.
Implement the delegate method in the primary View Controller
Add a delegate property in your scene so it can keep a handle to its ViewController's delegate method implementation. Set this delegate as the primary View Controller during the creation of the scene
Detect an event on the scene to call the delegate method of the primary ViewController
In the delegate method implementation pass the control to the TweetSheetViewController
Here's the example:
#protocol ViewControllerDelegate <NSObject>
-(void) openTweetSheet;
#end
Extend this ViewController to support this protocol in its .h file
#interface ViewController : UIViewController<ViewControllerDelegate>
#end
Then in the .m file implement the method from the protocol
-(void) openTweetSheet{
TweetSheetViewController *ctrl = [[TweetSheetViewController alloc] initWithNibName:#"TweetSheetViewController" bundle:nil];
[self presentViewController:ctrl animated:YES completion:nil];
}
In your Scene header class, add a delegate property
#interface MyScene : SKScene {
}
#property (nonatomic, weak) id <ViewControllerDelegate> delegate;
#end
In the ViewController, before presenting the scene set its delegate in viewDidLoad method:
// Create and configure the scene.
MyScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[scene setDelegate:self];
// Present the scene.
[skView presentScene:scene];
Now your Scene can pass the message back to its ViewController and the ViewController can open another ViewController. In your scene class, determine the action which will trigger the opening up of TweetSheetViewController
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
SKAction *fadeOut = [SKAction fadeOutWithDuration:0.5];
SKAction *fadeIn = [SKAction fadeInWithDuration:1.0];
SKAction *sequence = [SKAction sequence:#[fadeOut,fadeIn]];
SKNode *node = [self nodeAtPoint:location];
if ([[node name] isEqual: #"openTweet"]) {
NSLog(#"help");
[node runAction:sequence];
[delegate openTweetSheet];
}
}
Hope that helps.
Write the SlComposeViewController Method in the scene you want it to take place. For example:
#interface GameOverScene: SKScene
...initwithsize bla bla bla
...
Add these methods:
-(void)OpenTweetShet{
if ([SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter]) {
_composeTwitter = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[_composeTwitter setInitialText:#"TWEET"];
Then call:
self.view.window.rootViewController **to present the SLComposeViewController**
[self.view.window.rootViewController presentViewController:_composeTwitter animated:YES completion:nil];
}
[_composeTwitter setCompletionHandler:^(SLComposeViewControllerResult result){
NSString *output =[[NSString alloc]init];
switch (result) {
case SLComposeViewControllerResultCancelled:
output = #"Post cancelled";
break;
case SLComposeViewControllerResultDone:
output = #"Post Succesfull";
break;
default:
break;
}
Here is the option for presenting UIAlert after the send/cancel post:
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Twitter" message:output delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
}];
}
#end
This worked for me: self.view.window.rootViewController
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
NSArray *nodes = [self nodesAtPoint:[touch locationInNode:self]];
for (SKNode *node in nodes) {
if ([node.name isEqualToString:#"OpenTweet"]) {
UIViewController *vc = self.view.window.rootViewController;
[self.view.window.rootViewController openTweetSheet];
}
}
}

Making a button persistent across all view controllers

I want to have a persistent button in the bottom right corner of my app. During all view transitions, the button should remain static. I'm having trouble deciding what view to add the button to. I know the button ought to be stored in the AppDelegate, but I don't know what other view it would be sense to add it to except the window. One downside of adding it to the window is that when there's an app running in the background (ie Phone), the added status bar padding will push down the window. In general, adding it to the window seems to be a hacky solution -- any thoughts?
Yes, adding it to the UIWindow would be extremely hacky and finicky.
Storyboards
If you're using Storyboards and iOS 5.0 onwards, you should be able to use container views and do something like this:
Here's another picture showing the, rather simplistic, structure of the first View Controller:
The view controller on the left has a container, and then a view which holds the button on top of it. The container indicates that the navigation controller (directly to the right) should appear within itself, that relationship is shown by the =([])=> arrow (formally known as an embed segue). Finally the navigation controller defines its root view controller to the one on the right.
In summary, the first view controller pancakes-in the container view with the button on top, so everything that happens inside has to have the button on top.
Using childViewControllers
aka. The "I hate Storyboards and puppies" mode
Using a similar structure to the Storyboard version, you could create the base view controller with its button, and then, add the view that will become then new "root" of the application, underneath.
To make it clear, let's call the one view controller that holds the button the FakeRootViewController, and the view controller that will be, for all practical purposes, the root of the application: RootViewController. All subsequent view controllers won't even know that there's the FakeRootViewController above everyone else.
FakeRootViewController.m
// The "real" root
#import "RootViewController.h"
// Call once after the view has been set up (either through nib or coded).
- (void)setupRootViewController
{
// Instantiate what will become the new root
RootViewController *root = [[RootViewController alloc] <#initWith...#>];
// Create the Navigation Controller
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:root];
// Add its view beneath all ours (including the button we made)
[self addChildViewController:nav];
[self.view insertSubview:nav.view atIndex:0];
[nav didMoveToParentViewController:self];
}
AppDelegate.m
#import "FakeRootViewController.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
FakeRootViewController *fakeRoot = [[FakeRootViewController alloc] <#initWith...#>];
self.window.rootViewController = fakeRoot;
[self.window makeKeyAndVisible];
return YES;
}
That way, you can have all the benefits of inserting the button on the window, without all the guilt and "Should I really be a programmer?" that it causes.
Potentially you could have 1 main "root" view controller, and all you other view controllers could be child view controllers, with their views as child views. Then they would have their content, and the button would be in the "root" view controller. But this seems just as sketchy and hacky as putting it in the window, and probably less convenient.
I use this button:
#interface UIPopUpButton : UIImageView <UIPopoverControllerDelegate, UIActionSheetDelegate>
{
UIPopoverController* popoverController;
Class popoverClass;
}
- (id) initWithPoint: (CGPoint) point;
- (void) touchesBegan: (NSSet*) touches
withEvent: (UIEvent*) event;
+ (id) buttonAtPoint: (CGPoint) point;
+ (id) buttonAtOriginalPoint;
+ (void) unhighlight;
+ (void) bringButtonToFront;
#property (nonatomic, retain) UIPopoverController* popoverController;
#property (nonatomic, assign) Class popoverClass;
#end
#import "UIPopUpButton.h"
#implementation UIPopUpButton
static UIPopUpButton* button = nil;
static CGPoint originalPoint;
#synthesize popoverClass;
#synthesize popoverController;
+ (id) buttonAtPoint: (CGPoint) point
{
if (button == nil)
{
button = [[UIPopUpButton alloc] initWithPoint: point];
originalPoint = point;
button.popoverClass = [UIPopoverController class];
}
else
{
button.frame = CGRectMake(point.x, point.y, button.frame.size.width, button.frame.size.height);
}
return button;
}
+ (id) buttonAtOriginalPoint
{
return [self buttonAtPoint: originalPoint];
}
+ (void) unhighlight
{
button.highlighted = NO;
}
+ (void) bringButtonToFront
{
[[UIApplication sharedApplication].keyWindow addSubview: [self buttonAtOriginalPoint]];
}
- (id) initWithPoint: (CGPoint) point
{
UIImage* image1 = [UIImage imageNamed: #"topbutton.png"];
UIImage* image2 = [UIImage imageNamed: #"topbutton.png"];
if ((self = [super initWithImage: image1
highlightedImage: image2]))
{
self.userInteractionEnabled = YES;
self.frame = CGRectMake(point.x, point.y, self.frame.size.width, self.frame.size.height);
self.multipleTouchEnabled = NO;
}
return self;
}
- (BOOL) isAppCurrStatus
{
return ([DevToolsClientController sharedInstance].statusOfRootViewController == FrontEndApplication);
}
- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [touches anyObject];
if(touch.view == self)
{
if (self.popoverController == nil)
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
UIActionSheet* actionSheet = [[UIActionSheet alloc] initWithTitle: #"Please choice operation:"
delegate: self
cancelButtonTitle: nil
destructiveButtonTitle: nil
otherButtonTitles: nil];
[actionSheet addButtonWithTitle: #"Cancel"];
actionSheet.cancelButtonIndex = 0;
[actionSheet addButtonWithTitle: #"Button 1"];
actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
[actionSheet setTag: 0];
[actionSheet setDelegate: self];
[actionSheet showInView: [self superview]];
[actionSheet release];
[actions release];
}
else
{
PopoverMenuController* contentViewController = [[PopoverMenuController alloc] init];
self.popoverController = [[UIPopoverController alloc] initWithContentViewController: contentViewController];
popoverController.delegate = self;
[popoverController presentPopoverFromRect: CGRectMake(10.0f, 10.0f, 5.0f, 5.0f)
inView: self
permittedArrowDirections: UIPopoverArrowDirectionAny
animated: YES];
contentViewController.popoverController = self.popoverController;
[contentViewController reloadData];
}
}
else
{
[self.popoverController dismissPopoverAnimated:YES];
self.popoverController = nil;
}
}
[super touchesBegan: touches withEvent: event];
}
#pragma mark UIActionSheetDelegate implementation
-(void) actionSheet: (UIActionSheet*) actionSheet clickedButtonAtIndex: (NSInteger) buttonIndex
{
NSNumber* indexAction = [[NSNumber alloc] initWithInt: buttonIndex - 1];
}
- (void) runAction: (NSNumber*) indexAction
{
[DevToolsPopoverMenuController runAction: [indexAction integerValue]];
}
#pragma mark -
#pragma mark UIPopoverControllerDelegate implementation
- (void) popoverControllerDidDismissPopover: (UIPopoverController*) thePopoverController
{
if (self.popoverController != nil)
{
self.popoverController = nil;
}
}
- (BOOL) popoverControllerShouldDismissPopover: (UIPopoverController*) thePopoverController
{
//The popover is automatically dismissed if you click outside it, unless you return NO here
return YES;
}
#end
call:
[UIPopUpButton bringButtonToFront];
My button is always on top.
Try subclassing the UIViewController class and make your own one with the button
Create a singleton object that holds the button so all view controllers can reference it and add it to their subview or add it to the window directly.
SomeClass.h
#property (nonatomic) UIButton *yourButton;
+(SomeClass*)sharedSomeClass;
SomeClass.m
#synthesize yourButton = _yourButton;
-(id)init
{
self = [super init];
if(self)
{
_yourButton = [UIButton new];
//Other settings you want for your button
}
return self;
}
+(SomeClass)sharedSomeClass
{
static SomeClass *sharedSomeClass;
if (!sharedSomeClass)
sharedSomeClass = [[super allocWithZone:nil]init];
return sharedSomeClass;
}
+(void)allocWithZone:(NSZone*)zone
{
return [self sharedSomeClass];
}
If you like you can access the window directly like this:
UIWindow *mainwindow = [[[UIApplication sharedApplication]delegate]window];
import SomeClass.h into your view controllers, and access the button from anywhere
#import "SomeClass.h"
SomeClass *someClass = [SomeClass sharedSomeclass];
UIButton *localButton = someClass.yourButton;

Resources