Как представить UIViewController из SKScene?
Я вхожу в iOS через Sprite Kit, который я признаю неразумным.
Моя цель - отобразить кнопку "Поделиться" при игре. При нажатии кнопки общего доступа должен присутствовать SLComposeViewController (Twitter Share). Содержимое сцены не должно меняться.
Логика игры, которая диктует "Игра над", живет в SpriteMyScene.m, подклассе SKScene.
Я могу показать кнопку "Поделиться" в игре. Таким образом:
-(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];
}
Где я застрял, пытается заставить метод showTweetButton работать. Мой SpriteViewController.m выглядит так:
- (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.");
}];
}
Я всегда получаю что-то подобное в журналах:
- [UIView presentScene:]: непризнанный селектор отправлен в экземпляр 0x13e63d00 2013-10-17 18: 40: 01.611 Исправить [33409: a0b] * Завершение приложения из-за неперехваченного исключения "NSInvalidArgumentException", причина: '- [UIView presentScene:]: непризнанный селектор, отправленный в экземпляр 0x13e63d00
Ответы
Ответ 1
Вы создаете новый контроллер представления, но не представляете его:
SpriteViewController *viewController = [SpriteViewController alloc];
Я предполагаю, что SpriteViewController
представляет то, что представляет ваш SpriteMyScene
, и вы хотите передать управление представлению SpriteViewController
.
Вам нужно сохранить ссылку на SpriteViewController
в подклассе SpriteMyScene
, а затем получить доступ к этой ссылке при вызове openTweetSheet
.
в SpriteMyScene.h
@class SpriteViewController;
@interface SpriteMyScene : SKScene
@property (nonatomic, weak) SpriteViewController *spriteViewController;
@end
в SpriteViewController.m
// somewhere you initialize your SpriteMyScene object, I'm going to call it myScene
myScene.spriteViewController = self;
в SpriteMyScene.m
#import "SpriteViewController.h"
- (void)sendToController
{
NSLog(@"ok");
// use the already-created spriteViewController
[_spriteViewController openTweetSheet];
}
Ответ 2
Вы можете использовать
UIViewController *vc = self.view.window.rootViewController;
Этот код предоставит вам доступ к вашему контроллеру корневого представления, чтобы вы могли делать все, что у вас есть, будет ли ваш контроллер просмотра нормальным.
Однако вам нужно добавить кнопку? Используйте спрайт и добавьте в него событие, в этом случае вам лучше. Просто позвоните:
UIViewController *vc = self.view.window.rootViewController;
[vc openTweetSheet];
И
-(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];
}
}
}
Ответ 3
Если вы хотите открыть другой UIViewController внутри вашей сцены, вам сначала нужно создать делегат в основном контроллере просмотра, который изначально создавал эту сцену, чтобы ваша сцена могла уведомить свой ViewController о действии открытого твита. Вам понадобятся следующие шаги:
- Определите делегата в основном контроллере представления - контроллере представления нашей сцены, чтобы обработать открытое действие твита.
- Реализация метода делегата в основном контроллере представления
- Добавить свойство делегата в вашей сцене, чтобы он мог сохранить дескриптор реализации метода делегирования ViewController. Установите этот делегат в качестве основного контроллера просмотра во время создания сцены.
- Обнаружение события на сцене для вызова метода делегата основного ViewController
- В реализации метода делегата передайте элемент управления TweetCheetViewController
Вот пример:
@protocol ViewControllerDelegate <NSObject>
-(void) openTweetSheet;
@end
Расширить этот ViewController для поддержки этого протокола в его .h файле
@interface ViewController : UIViewController<ViewControllerDelegate>
@end
Затем в файле .m реализует метод из протокола
-(void) openTweetSheet{
TweetSheetViewController *ctrl = [[TweetSheetViewController alloc] initWithNibName:@"TweetSheetViewController" bundle:nil];
[self presentViewController:ctrl animated:YES completion:nil];
}
В классе заголовка Scene добавьте свойство делегата
@interface MyScene : SKScene {
}
@property (nonatomic, weak) id <ViewControllerDelegate> delegate;
@end
В ViewController перед представлением сцены установите свой делегат в методе viewDidLoad:
// Create and configure the scene.
MyScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[scene setDelegate:self];
// Present the scene.
[skView presentScene:scene];
Теперь ваша сцена может передать сообщение обратно в ViewController, и ViewController может открыть другой ViewController. В своем классе сцены определите действие, которое вызовет открытие 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];
}
}
Надеюсь, что это поможет.
Ответ 4
Напишите метод SlComposeViewController в сцене, которую вы хотите, чтобы он состоялся. Например:
@interface GameOverScene: SKScene
...initwithsize bla bla bla
...
Добавьте следующие методы:
-(void)OpenTweetShet{
if ([SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter]) {
_composeTwitter = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[_composeTwitter setInitialText:@"TWEET"];
Затем вызовите:
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;
}
Вот вариант представления UIAlert после сообщения send/cancel:
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Twitter" message:output delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil];
[alert show];
}];
}
@end
Ответ 5
Это сработало для меня: 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];
}
}
}