iOS 3D Touch in Objective C - ios

Any one have any idea how can we implement 3d touch feature in objective C? I already check the app documentation but no example is related to objective C code.
Any sample code or example, how to implement ? Thanks in Advance.

The way I am doing this is to use a DFContinuousForceTouchGestureRecognizer that I have made available. This is a gesture recognizer extension that detects force touch and works alongside other gesture recognizers.
The DFContinuousForceTouchGestureRecognizer provides continuous updates about the pressure changes so you can do nice things like augment the view as the user varies their pressure on it, as opposed to just triggering a single event. If you just want a single event you can ignore eveything in the DFContinuousForceTouchDelegate except the - (void) forceTouchRecognized callback.
https://github.com/foggzilla/DFContinuousForceTouchGestureRecognizer
You can download this and run the sample app on a device that supports force press to see how it feels.
In your UIViewController implement:
- (void) viewDidLoad {
[super viewDidLoad];
_forceTouchRecognizer = [[DFContinuousForceTouchGestureRecognizer alloc] init];
_forceTouchRecognizer.forceTouchDelegate = self;
[self.imageView addGestureRecognizer:_forceTouchRecognizer];
}
implement the delegate protocol for force touch:
#pragma DFContinuousForceTouchDelegate
- (void) forceTouchRecognized:(DFContinuousForceTouchGestureRecognizer*)recognizer {
self.imageView.transform = CGAffineTransformIdentity;
[self.imageView setNeedsDisplay];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[[UIAlertView alloc] initWithTitle:#"Force Touch" message:#"YEAH!!" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
});
}
- (void) forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer*)recognizer didStartWithForce:(CGFloat)force maxForce:(CGFloat)maxForce {
CGFloat transformDelta = 1.0f + ((force/maxForce) / 3.0f);
self.imageView.transform = CGAffineTransformMakeScale(transformDelta, transformDelta);
[self.imageView setNeedsDisplay];
}
- (void) forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer*)recognizer didMoveWithForce:(CGFloat)force maxForce:(CGFloat)maxForce {
CGFloat transformDelta = 1.0f + ((force/maxForce) / 3.0f);
self.imageView.transform = CGAffineTransformMakeScale(transformDelta, transformDelta);
[self.imageView setNeedsDisplay];
}
- (void) forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer*)recognizer didCancelWithForce:(CGFloat)force maxForce:(CGFloat)maxForce {
self.imageView.transform = CGAffineTransformIdentity;
[self.imageView setNeedsDisplay];
}
- (void) forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer*)recognizer didEndWithForce:(CGFloat)force maxForce:(CGFloat)maxForce {
self.imageView.transform = CGAffineTransformIdentity;
[self.imageView setNeedsDisplay];
}
- (void) forceTouchDidTimeout:(DFContinuousForceTouchGestureRecognizer*)recognizer {
self.imageView.transform = CGAffineTransformIdentity;
[self.imageView setNeedsDisplay];
}
Note that this will only be useful on a device that supports force touch.
Also you should not add the UIContinuousForceTouchGestureRecognizer to a view if are you running on iOS8 or under since it uses the new force property on UITouch only available in iOS9.
If you add this on iOS8 it will crash, so conditionally add this recognizer based on what iOS version you are running on if you are supporting versions older than iOS9.

Here is an example adapted from yeungkaho's example on github
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self handleTouches:touches];
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self handleTouches:touches];
}
-(void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self setForcePercentage:0];
}
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self setForcePercentage:0];
}
-(void)handleTouches:(NSSet<UITouch *> *)touches{
for (UITouch *touch in touches) {
CGFloat force = touch.force;
CGFloat percentage = force/touch.maximumPossibleForce;
[self setForcePercentage:percentage];
break;
}
}
-(void)setForcePercentage:(CGFloat)percentage{
NSLog(#"LEVEL = %f",percentage*100);
}

I am sharing the source code for pressing on app icon populate 4 item in list
Step 1:- Import class in appDelegate.m
import sys/utsname.h
Step 2:-
#pragma MARK for Get Machine Name
- (NSString *) machineName {
struct utsname systemInfo;
uname(&systemInfo);
return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if([[self machineName] isEqualToString:#"iPhone8,2"]|| [[self machineName] isEqualToString:#"iPhone8,1"]) {
[self addEventsFor3DTouchEvents];
}
return YES;
}
pragma MARK for Adding Action for Three D Touch Events
- (void) addEventsFor3DTouchEvents {
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9.0) {
UIApplicationShortcutItem *item1 = [[UIApplicationShortcutItem alloc] initWithType:#"dynamic1" localizedTitle:TITLE_NAME_1 localizedSubtitle:#"" icon:[UIApplicationShortcutIcon iconWithTemplateImageName:TITLE_IMAGE_NAME_1] userInfo:nil];
UIApplicationShortcutItem *item2 = [[UIApplicationShortcutItem alloc] initWithType:#"dynamic1" localizedTitle:TITLE_NAME_2 localizedSubtitle:#"" icon:[UIApplicationShortcutIcon iconWithTemplateImageName:TITLE_IMAGE_NAME_2] userInfo:nil];
UIApplicationShortcutItem *item3 = [[UIApplicationShortcutItem alloc] initWithType:#"dynamic1" localizedTitle:TITLE_NAME_3 localizedSubtitle:#"" icon:[UIApplicationShortcutIcon iconWithTemplateImageName:TITLE_IMAGE_NAME_3] userInfo:nil];
UIApplicationShortcutItem *item4 = [[UIApplicationShortcutItem alloc] initWithType:#"dynamic1" localizedTitle:TITLE_NAME_4 localizedSubtitle:#"" icon:[UIApplicationShortcutIcon iconWithTemplateImageName:TITLE_IMAGE_NAME_4] userInfo:nil];
[[UIApplication sharedApplication] setShortcutItems: #[ item1, item2, item3, item4 ]];
}
}
#pragma mark - 3DTouch Delegate Methods
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL))completionHandler {
[self moveThrough3DTouch:shortcutItem];
}
#pragma MARK for Handling Action for Three D Touch Events
- (void)moveThrough3DTouch:(UIApplicationShortcutItem *)temp {
if ([temp.localizedTitle isEqualToString:TITLE_NAME_1]) {
[self.tabBarController setSelectedIndex:0];
} else if([temp.localizedTitle isEqualToString:TITLE_NAME_2]) {
[self.tabBarController setSelectedIndex:1];
} else if([temp.localizedTitle isEqualToString:TITLE_NAME_3]) {
[self.tabBarController setSelectedIndex:2];
} else if([temp.localizedTitle isEqualToString:TITLE_NAME_4]) {
[self.tabBarController setSelectedIndex:3];
}
}
**I am using Tab Bar controller in my app, If want to move in view controlled
- (void) moveToControllerScene {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:STORY_BOARD_IDENTIFIER bundle:nil];
YOUR_CONTROLLER_OBJECT *obj = [storyboard instantiateViewControllerWithIdentifier:#"YOUR_CONTROLLER_OBJECT"];
[navController pushViewController:obj animated:YES];
}

Related

willRotateToInterfaceOrientation:duration is deprecated. Implement viewWillTransitionToSize:withTransitionCoordinator

I got a list of deprecated warning once I updated my xcode to xcode9 and I have no Idea how to fix it
'willRotateToInterfaceOrientation:duration:' is deprecated: first deprecated in iOS 8.0 - Implement viewWillTransitionToSize:withTransitionCoordinator: instead
'willAnimateRotationToInterfaceOrientation:duration:' is deprecated: first deprecated in iOS 8.0 - Implement viewWillTransitionToSize:withTransitionCoordinator: instead
'didRotateFromInterfaceOrientation:' is deprecated: first deprecated in iOS 8.0
'interfaceOrientation' is deprecated: first deprecated in iOS 8.0
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.view addObserver:self forKeyPath:#"bounds" options:NSKeyValueObservingOptionNew context:nil];
if (!_viewFirstAppeared) {
_viewFirstAppeared = YES;
void(^applyViews)(void) = ^{
[self.centerController.view removeFromSuperview];
[self.centerView addSubview:self.centerController.view];
[self doForControllers:^(UIViewController* controller, IIViewDeckSide side) {
[controller.view removeFromSuperview];
[self.referenceView insertSubview:controller.view belowSubview:self.slidingControllerView];
}];
[self setSlidingFrameForOffset:_offset forOrientation:_offsetOrientation];
self.slidingControllerView.hidden = NO;
self.centerView.frame = self.centerViewBounds;
self.centerController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.centerController.view.frame = self.centerView.bounds;
[self doForControllers:^(UIViewController* controller, IIViewDeckSide side) {
controller.view.frame = self.sideViewBounds;
controller.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}];
[self applyShadowToSlidingViewAnimated:NO];
};
if ([self setSlidingAndReferenceViews]) {
applyViews();
applyViews = nil;
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.001 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void){
if (applyViews) applyViews();
[self setSlidingFrameForOffset:_offset forOrientation:_offsetOrientation];
[self hideAppropriateSideViews];
});
[self addPanners];
if ([self isSideClosed:IIViewDeckLeftSide] && [self isSideClosed:IIViewDeckRightSide] && [self isSideClosed:IIViewDeckTopSide] && [self isSideClosed:IIViewDeckBottomSide])
[self centerViewVisible];
else
[self centerViewHidden];
}
else if (_willAppearShouldArrangeViewsAfterRotation != UIDeviceOrientationUnknown) {
for (NSString* key in [self.view.layer animationKeys]) {
[self.view.layer animationForKey:key].duration);
}
[self willRotateToInterfaceOrientation:self.interfaceOrientation duration:0];
[self willAnimateRotationToInterfaceOrientation:self.interfaceOrientation duration:0];
[self didRotateFromInterfaceOrientation:_willAppearShouldArrangeViewsAfterRotation];
}
[self.centerController viewWillAppear:animated];
[self transitionAppearanceFrom:0 to:1 animated:animated];
_viewAppeared = 1;
}
I was just searching for the same exact thing and found something in iOS documentation and after reading it and since I have users who still have iOS 8. I kept the old two function and add the new one to it.
// old ones
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
[self handleInterfaceOrientation];
}
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
[self handleInterfaceOrientation];
}
// the new method
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
// what ever you want to prepare
} completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
[self handleInterfaceOrientation];
}];
}
- (void)handleInterfaceOrientation {
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight) {
// Landscape
} else {
// Portrait
}
}

UIMenuController's canPerformAction method called on button tap

I have a message view in which user can see conversation and type & send message. Menu (kind of context menu) is displayed when user long taps on message. I have used TableView and Button for chat history and send message button respectively.
My problem is canPerformAction:withSender method is hit when I tap on Button or TableView. And moreover this code was working fine till iOS 9.0.
#interface MessageDetailViewController ()
- (void)updateDetailView;
- (void)setMessageBar;
- (void)setCallButton;
#end
#implementation MessageDetailViewController
{
}
#synthesize messageField;
#synthesize messageList;
#synthesize messageBarView;
#synthesize navigationBarView;
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"MessageDetailView: viewDidLoad method called.");
// Observe keyboard hide and show notifications to resize the text view appropriately.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didHideEditMenu:) name:UIMenuControllerDidHideMenuNotification object:nil];
[messageField becomeFirstResponder];
messageArray = [[NSMutableArray alloc] init];
typingImage = [[UIImageView alloc] init];
presenceImage = [[UIImageView alloc] init];
navigationBarView = [[UIView alloc] init];
viewHeight = self.view.frame.size.height;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[messageField setDelegate:self];
messageList.delegate = self;
messageList.dataSource = self;
[self updateDetailView];
[messageList reloadData];
}
- (BOOL)canBecomeFirstResponder
{
return YES;
}
/**
* This method is called to send instance method to server.
*/
- (void)onSendMessageButtonPressed:(id)sender
{
if([messageField.text length] == 0)
{
return;
}
messageField.text = [messageField.text substringToIndex:160];
[[DatabaseManager getDatabaseManager] addMessageInDatabase:messageField.text];
[messageField setText:#""];
[self updateDetailView];
[messageList reloadData];
}
-(void)handleLongPress : (UILongPressGestureRecognizer *)gesture
{
TableViewCell *cell = nil;
UIMenuController *menu = [UIMenuController sharedMenuController];
if(gesture.state == UIGestureRecognizerStateBegan)
{
CGPoint p = [gesture locationInView:self.messageList];
NSIndexPath *ip = [self.messageList indexPathForRowAtPoint:p];
rowPosition = ip.row;
NSLog(#"row = %d", ip.row);
if(ip)
{
cell = (TableViewCell *)[messageList cellForRowAtIndexPath:ip];
[self becomeFirstResponder];
[menu setMenuItems:nil];
UIMenuItem *copyMenuItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(#"COPY_MESSAGE", #"") action:#selector(copyMessage:)] autorelease];
UIMenuItem *deleteMenuItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(#"DELETE_MESSAGE", #"") action:#selector(deleteMessage:)] autorelease];
if(cell.imFailIndication.image != nil)
{
UIMenuItem *resendMenuItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(#"RESEND_MESSAGE", #"") action:#selector(resendMessage:)] autorelease];
[menu setMenuItems:[NSArray arrayWithObjects:copyMenuItem, deleteMenuItem, resendMenuItem, nil]];
}
else
{
[menu setMenuItems:[NSArray arrayWithObjects:copyMenuItem, deleteMenuItem, nil]];
}
[menu setTargetRect:cell.frame inView:cell.superview];
[menu setMenuVisible:YES animated:YES];
return;
}
}
}
- (void)copyMessage:(id)sender
{
MessageDetailInfo *detailMessageInfo = [messageArray objectAtIndex:rowPosition];
[UIPasteboard generalPasteboard].string = detailMessageInfo.message;
}
- (void)deleteMessage:(id)sender
{
messageDeleteActionSheet = [[UIActionSheet alloc] initWithTitle:NSLocalizedString(#"PROMPT_MESSAGE_DELETE_CONFIRMATION", #"") delegate:self cancelButtonTitle:NSLocalizedString(#"CANCEL_BTN_TITLE", #"") destructiveButtonTitle:NSLocalizedString(#"DELETE_BTN_TITLE", #"") otherButtonTitles:nil, nil];
[messageDeleteActionSheet showFromTabBar:self.tabBarController.tabBar];
}
/*
The view implements this method to conditionally enable or disable commands of the editing menu.
The canPerformAction:withSender method is declared by UIResponder.
*/
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
UIMenuController *menu = (UIMenuController *)sender;
switch ([[menu menuItems] count])
{
case 0:
//This case is to display paste option for Message text field.
if(action == #selector(paste:))
{
return YES;
}
break;
case 2:
if(action == #selector(copyMessage:) || action == #selector(deleteMessage:))
{
return YES;
}
break;
case 3:
if(action == #selector(copyMessage:) || action == #selector(deleteMessage:) || action == #selector(resendMessage:))
{
return YES;
}
break;
default:
break;
}
return NO;
}
- (void)keyboardWillShow:(NSNotification *)notification
{
/*
Reduce the size of the text view so that it's not obscured by the keyboard.
Animate the resize so that it's in sync with the appearance of the keyboard.
*/
NSDictionary *userInfo = [notification userInfo];
// Get the origin of the keyboard when it's displayed.
NSValue* aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
// Get the top of the keyboard as the y coordinate of its origin in self's view's coordinate system. The bottom of the text view's frame should align with the top of the keyboard's final position.
CGRect keyboardRect = [aValue CGRectValue];
// Get the duration of the animation.
NSValue *animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval animationDuration;
[animationDurationValue getValue:&animationDuration];
// Animate the resize of the text view's frame in sync with the keyboard's appearance.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:animationDuration];
/* change position of messageBarView based on visibility of keypadview. */
CGRect messageBarFrame = messageBarView.frame;
messageBarFrame.origin.y = viewHeight - keyboardRect.size.height - messageBarView.frame.size.height;
messageBarView.frame = messageBarFrame;
if(messageBarFrame.origin.y == (viewHeight - keyboardRect.size.height - messageBarView.frame.size.height))
{
[messageField becomeFirstResponder];
}
/* change height of messageList based on visibility of keypadView. */
CGRect messageListFrame = messageList.frame;
messageListFrame.size.height = messageBarView.frame.origin.y;
messageList.frame = messageListFrame;
[UIView commitAnimations];
/* scroll to table view at last message if messages are available. */
if ([messageList numberOfRowsInSection:0])
{
[messageList scrollToRowAtIndexPath:[NSIndexPath indexPathForRow ([messageList numberOfRowsInSection:0] - 1) inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
}
- (void)keyboardWillHide:(NSNotification *)notification
{
NSDictionary* userInfo = [notification userInfo];
/*
Restore the size of the text view (fill self's view).
Animate the resize so that it's in sync with the disappearance of the keyboard.
*/
NSValue *animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval animationDuration;
[animationDurationValue getValue:&animationDuration];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:animationDuration];
/* change position of messageBarView based on visibility of keypadview. */
CGRect newFrame = messageBarView.frame;
newFrame.origin.y = self.view.frame.size.height - messageBarView.frame.size.height;
messageBarView.frame = newFrame;
/* Don't update tableview if datasource has been set nil. */
if(messageList.dataSource != nil)
{
/* change height of messageList based on visibility of keypadView. */
CGRect messageListFrame = messageList.frame;
messageListFrame.size.height = messageBarView.frame.origin.y;
messageList.frame = messageListFrame;
}
[UIView commitAnimations];
}
- (void)didHideEditMenu:(NSNotification *)notification
{
[[UIMenuController sharedMenuController] setMenuItems:nil];
}
- (void)didReceiveMemoryWarning
{
/* Releases the view if it doesn't have a superview. */
[super didReceiveMemoryWarning];
/* Release any cached data, images, etc that aren't in use. */
}
- (void)viewDidUnload
{
[super viewDidUnload];
/* Release any retained subviews of the main view.
e.g. self.myOutlet = nil; */
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerDidHideMenuNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
messageList.delegate = nil;
messageList.dataSource = nil;
}
-(BOOL)navigationShouldPopOnBackButton
{
NSLog(#"navigationShouldPopOnBackButton appearedFromComposeView = %d", [[NSNumber numberWithBool:appearedFromComposeView] intValue]);
if(appearedFromComposeView)
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
return YES; // Process 'Back' button click and Pop view controler
}
- (void)dealloc
{
[messageField release];
[messageList release];
[messageBarView release]
[messageArray release];
[super dealloc];
}
#end

How to show leaderboard in iOS 7

I am using sprite-kit and targeted iOS 7. I want to show leaderboard with button in my MenuScene.
my helper method codes.
#import "GameKitHelper.h"
NSString *const PresentAuthenticationViewController =
#"present_authentication_view_controller";
#interface GameKitHelper()<GKGameCenterControllerDelegate>
#end
#implementation GameKitHelper {
BOOL _enableGameCenter;
}
+ (instancetype)sharedGameKitHelper
{
static GameKitHelper *sharedGameKitHelper;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedGameKitHelper = [[GameKitHelper alloc] init];
});
return sharedGameKitHelper;
}
- (id)init
{
self = [super init];
if (self) {
_enableGameCenter = YES;
}
return self;
}
- (void)showGKGameCenterViewController:
(UIViewController *)viewController
{
if (!_enableGameCenter) {
NSLog(#"Local play is not authenticated");
}
GKGameCenterViewController *gameCenterViewController =
[[GKGameCenterViewController alloc] init];
gameCenterViewController.gameCenterDelegate = self;
gameCenterViewController.viewState =
GKGameCenterViewControllerStateAchievements;
[viewController presentViewController:gameCenterViewController
animated:YES
completion:nil];
}
I want to Leaderboard Button in this class.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"start"]) {
MyScene *myScene = [MyScene sceneWithSize:self.size];
[self.view presentScene:myScene transition:[SKTransition pushWithDirection:SKTransitionDirectionLeft duration:0.5]];
}
if ([node.name isEqualToString:#"gameCenter"]) {
//HERE MY LEADERBOARD BUTTON ACTION
//I don't know what i write here...
{
}
I tried so much methods but these working in iOS 6, I targeted iOS 7.
I tried this:
[[GameKitHelper sharedGameKitHelper] showGKGameCenterViewController:self]; Xcode says for self
Incompatible pointer types sending 'GameMenuScene *' to parameter of type 'UIViewController *'
Andrey is right. gameKitHelper means [gameKitHelper sharedGameKitHelper]. like this example
if ([node.name isEqualToString:#"gameCenter"]) {
UIViewController *vc = self.view.window.rootViewController;
[[GameKitHelper sharedGameKitHelper] showGKGameCenterViewController:vc];
}
Keep coding :)
if ([node.name isEqualToString:#"gameCenter"]) {
UIViewController *vc = self.view.window.rootViewController;
[[GameKitHelper sharedGameKitHelper] showGKGameCenterViewController:vc];
}
But actually you should present another ViewController from your ViewController, not from SKScene
Try this, it's easy to implement and works well:
https://github.com/nihalahmed/GameCenterManager
inside viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(openLeaderboard)
name:#"TestNotification"
object:nil];
Inside VC:
- (void) openLeaderboard
{
// Open Leaderboards here
}
In your Scene:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"TestNotification"
object:self];

Stop a UITableView from reloading data on orientation change

My uitableview calls reloaddata when the orientation of the device changes (makes sense, since the number of cells displayed changes, is called in layout subviews as far as I could understand from the documentation), however this is problematic for me, because I am performing a download in the background and I don't want some of the files to suddenly appear. Is there a way to stop the default behaviour and let me reload manually when I want to?
EDIT:
I will try to explain better. on the top of my tableview, I have a button called "sync" which starts a syncing request from the server, this sync request first get a JSON object, which holds the information I would like to display in the tableview, but each of the uitableview items represents a file I'm downloading from the internet.
While the files are downloading I have an activity indicator on screen, only when the files finish downloading I want to reload the table. The problem is, the UITableview automatically calls reloaddata when the user changes orientation, so the cells fill with the information from the json before the downloaded files finished downloading.
code:
#implementation BIDManageFilesViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(newDataFinishedDownloading) name:kBIDContentManagerContentDidChangeNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(newDataStartedDownloading:) name:kBIDContentManagerStartedDownloadingContent object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(contentAlreadyUpToDate) name:kBIDContentUpToDate object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(contentStartingSync) name:kBIDContentStartingSync object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(contentEndingSync) name:kBIDContentEndingSync object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(singleDownloadFinished) name:kBIDFinishedDownloadingSingleContent object:nil];
self.navigationController.navigationBarHidden = NO;
UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithTitle:#"Sync"
style:UIBarButtonItemStyleDone target:self action:#selector(Sync)];
self.navigationItem.leftBarButtonItem = leftButton;
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:#"Display Mode"
style:UIBarButtonItemStyleDone target:self action:#selector(dismissSelf)];
self.navigationItem.rightBarButtonItem = rightButton;
self.navigationItem.title = #"Content Manager";
self.navigationBar = [[UINavigationBar alloc] initWithFrame:CGRectZero];
[self.view addSubview:_navigationBar];
[self.navigationBar pushNavigationItem:self.navigationItem animated:NO];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
}
-(void)layoutNavigationBar{
if([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortraitUpsideDown)
{
self.navigationBar.frame = CGRectMake(0, self.tableView.contentOffset.y, self.view.frame.size.width, self.topLayoutGuide.length + 44);
}
else
{
self.navigationBar.frame = CGRectMake(0, self.tableView.contentOffset.y, self.view.frame.size.height, self.topLayoutGuide.length + 44);
}
NSLog(#"width: %f", self.view.frame.size.width);
NSLog(#"height: %f", self.view.frame.size.height);
self.tableView.contentInset = UIEdgeInsetsMake(self.navigationBar.frame.size.height, 0, 0, 0);
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
//no need to call super
[self layoutNavigationBar];
}
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self layoutNavigationBar];
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
-(void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
[self layoutNavigationBar];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a story board-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.navigationController.navigationBarHidden = YES;
}
-(void)newDataStartedDownloading: (NSNotification *)notif
{
self.hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
_hud.labelText = #"Downloading...";
_hud.detailsLabelText = [NSString stringWithFormat:#"1/%#",[notif.userInfo objectForKey:#"downloadFileNumber"]];
}
-(void)singleDownloadFinished
{
NSString *currentText = _hud.detailsLabelText;
NSArray *subStrings = [currentText componentsSeparatedByString:#"/"];
NSInteger downloadsPlusOne = [[subStrings objectAtIndex:0] integerValue]+1;
NSString *newTextForLabel = [NSString stringWithFormat:#"%d/%#", downloadsPlusOne, [subStrings objectAtIndex:1]];
_hud.detailsLabelText = newTextForLabel;
}
-(void)newDataFinishedDownloading
{
_thereIsNewInfo = TRUE;
[MBProgressHUD hideHUDForView:self.view animated:YES];
[self.tableView reloadData];
[[NSNotificationCenter defaultCenter] postNotificationName:kBIDnewDownloadedContentReadyToBeDispayedNotification object:nil userInfo:nil];
}
-(void)contentAlreadyUpToDate
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Sync Alert"
message:#"Files Are Already Up To Date"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
}
-(void)contentStartingSync
{
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = #"Syncing...";
}
-(void)contentEndingSync
{
[MBProgressHUD hideHUDForView:self.view animated:YES];
}
-(void)Sync
{
[AppDelegate.appContentManager downloadContent];
}
-(void)dismissSelf
{
if (![AppDelegate.appContentManager subsetArrayFromFileArrayWithNonVidContentThatShouldDisplay] && ![AppDelegate.appContentManager subsetArrayFromFileArrayWithVideoContentThatShouldDisplay]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No Files to Display"
message:#"Please update or enable content"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
return;
}
else if ([AppDelegate.appContentManager subsetArrayFromFileArrayWithNonVidContentThatShouldDisplay])
{
[self dismissViewControllerAnimated:YES completion:Nil];
}
else
{
[self performSegueWithIdentifier:#"goToVideos" sender:self];
}
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"goToVideos"])
{
((BIDViewController *)segue.destinationViewController).stackedByManager = TRUE;
}
}
#end
It's not necessary to reloaddata on orientation change but if you want to reload table try to call [myTable reloadData] after the completion of the background download and only if the orientation has changed (you can set a bool for this on orient. change).

How to implement "finger-tracing" layer in app like the iOS Simulator

Now that our app has shipped, our person in charge of training has a request:
"The app is cool, but we need a mode showing the movement of the fingers, like how gestures show up in the Simulator or iPad's laser pointer mode in Keynote [so we can capture films]."
This is an app that uses a UITabBarController with xibs for each tab (4). This is a pretty complicated app with interacting gesture recognizers and I was having "first, do no harm" nightmares...
I tried adding a simple "global UIView" above the tab controller using the scheme here: http://www.james-vandyne.com/creating-universal-overlays-using-uiviews-on-ios/
My "PresentationView" attempt:
in my app delegate:
UIWindow *mainWindow = [[UIApplication sharedApplication] keyWindow];
[self setPresentationView:[[PresentationView alloc] initWithFrame: [mainWindow frame]]];
[mainWindow insertSubview:presentationView aboveSubview:mainWindow];
The class:
// PresentationView.h
#import <UIKit/UIKit.h>
#interface PresentationView : UIView
{
NSMutableDictionary *touchesInView;
}
#property (nonatomic, retain) NSMutableDictionary *touchesInView;
#end
#import "PresentationView.h"
#import "TouchPoint.h"
#implementation PresentationView
#synthesize touchesInView;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[ self setAlpha:0.1];
[self setBackgroundColor:[UIColor whiteColor]];
[self setUserInteractionEnabled:YES];
[self setMultipleTouchEnabled:YES];
touchesInView = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void) dealloc
{
[touchesInView release];
touchesInView = nil;
[super dealloc];
}
- (void)drawRect:(CGRect)rect
{
if ([touchesInView count] < 1)
return;
CGContextRef context = UIGraphicsGetCurrentContext();
NSEnumerator *touchEnum = [touchesInView objectEnumerator];
TouchPoint *nextTouch;
float rad = 24;
while (nextTouch = [touchEnum nextObject]) {
[[ UIColor redColor] set];
CGContextAddArc(context, nextTouch.current.x, nextTouch.current.y, rad, 0.0, M_PI*2, 1);
CGContextFillPath(context);
CGContextStrokePath(context);
}
}
- (UIView *) hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
[self setNeedsDisplay];
return [[[[[UIApplication sharedApplication] keyWindow] subviews] objectAtIndex:0] hitTest:point withEvent:event];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for( UITouch *t in touches )
{
NSValue *key = [NSValue valueWithPointer:t];
CGPoint loc = [t locationInView:self];
TouchPoint *newTouch = [[TouchPoint alloc] init];
[newTouch setBegan:loc];
[newTouch setCurrent:loc];
[newTouch setTapCount:[t tapCount]];
[touchesInView setObject:newTouch forKey:key];
[newTouch release];
}
[self setNeedsDisplay];
[[[[[UIApplication sharedApplication] keyWindow] subviews] objectAtIndex:0] touchesBegan:touches withEvent:event];
}
// More touch methods- all ignored
This kinda works- the view sits atop all the other views, and hitTest:withEvent: fires, and I was successfully drawing a red circle at the hit point in drawRect:.
But it breaks down when I try to track touches- touchesBegan/Moved/Ended don't fire. (Yes, I have turned on UserInteractionEnabled and setMultipleTouchEnabled for this global view). Fortunately, I haven't screwed up gesture recognition on anything below- the other views are getting events, and the app is behaving normally under this global view.
Normally I use IB to build/locate views and don't build them in code from scratch, so it's very possible there's (a?/several?) simple UIView properties I'm not setting up right... but I can't see it. Or am I going to get myself in trouble with this, trying to forward events down the chain?
There's a good framework called FingerTips that does this.
It's also easy to implement and it only shows the circles if there is an external display so you are presenting it.

Resources