How to remove the shadow of the centerViewController on IIViewDeckController 2.2.11 ? I know I have to use a delegate that implements the viewDeckController:applyShadow:withBounds: selector. But I don't know how to do that.
If someone can help me. Thank you
There is a property in the IIViewDeckController called 'shadowEnabled' simply set it to NO in your IIViewDeckController instance variable.
Alternatively in your Storyboard or .Xib file, you can add a User Defined Runtime Attribute with 'shadowEnabled' as the Key Path, 'Boolean' as the type and uncheck the value (making it NO/False)
So I found the solution for the version 2.2.11.
I added this to AppDelegate.h:
#import "IIViewDeckController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate, IIViewDeckControllerDelegate>
In AppDelegate.m, in didFinishLaunchingWithOptions class:
deckController.delegate = self;
Then I added the viewDeckController:applyShadow:withBounds: selector to the end of AppDelegate.m:
- (void)viewDeckController:(IIViewDeckController *)viewDeckController applyShadow:(CALayer *)shadowLayer withBounds:(CGRect)rect {
shadowLayer.masksToBounds = NO;
shadowLayer.shadowRadius = 0;
shadowLayer.shadowOpacity = 0;
shadowLayer.shadowColor = nil;
shadowLayer.shadowOffset = CGSizeZero;
shadowLayer.shadowPath = nil;
}
Related
The following code won't compile because of the error that results from trying to set the GKLeaderboardViewController delegate to the calling instance.
The error message is:
Assigning to 'id<UINavigationControllerDelegate>' from incompatible type 'MainMenu *'
where MainMenu is of type CCLayer.
If the assignment statement (leaderboard.delegate = self) is commented out, the code will compile, the leaderboard will display, but the callback will not be called when the "done" button is pressed.
This is the code:
- (void) showLeaderBoard {
// Show GC leaderboard
GKLeaderboardViewController *leaderboard = [[GKLeaderboardViewController alloc] init];
if (leaderboard != nil) {
leaderboard.delegate = self;
leaderboard.category = #"ldrbrd_ref";
AppController *app = (AppController *)[[UIApplication sharedApplication] delegate];
[[app navController] presentViewController:leaderboard animated:YES completion:nil];
}
}
Incidentally, this is my header for the object declaration:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "CCGameButton.h"
#import <GameKit/GameKit.h>
#interface MainMenu : CCLayer <CCGameButtonDelegate, GKLeaderboardViewControllerDelegate> {
}
+ (CCScene *) scene;
#end
What am I doing wrong? Any help appreciated!
I believe what you are looking for is the leaderboardDelegate property rather than the delegate property. leaderboardDelegate requires a <GKLeaderboardViewControllerDelegate> while delegate requires a <UINavigationControllerDelegate>, hence the error message.
Check the apple docs for leaderboardDelegate
https://developer.apple.com/library/ios/documentation/GameKit/Reference/GKLeaderboardViewController_Ref/#//apple_ref/occ/instp/GKLeaderboardViewController/leaderboardDelegate
Now I'm not sure if this is possible in Objective-C but I would expect it should be.
I have multiple images across my storyboard using the following/similar code on UIImages
cell.followingImage.layer.cornerRadius = cell.followingImage.frame.size.width / 2;
cell.followingImage.clipsToBounds = YES;
I want to optimise the code. I know you can apply classes to objects but I have never done this before. Is it possible to apply the class via the storyboard and automatically run that code without referencing and adding it to every controller?
So if a class is attached to the UIImage it would just run that code and make the UIImage a circle? This is probably really simple...
If I was to subclass a UIimage I'm not sure where to put the above code?
Try making a category of UIImage. Include everything you want in this custom category class like your cornerRadius and your clipToBounds code. Then when you init the images, don't init the images with [UIImage new] but with [customImageCategoryName new[. Now, all these images will, by default, have those two lines of code. The following link will show you how to create a category in Xcode How do I create a category in Xcode 6 or higher?
Do place that code in
-(instancetype)initWithCoder:(NSCoder *)aDecoder method , -(instancetype)initWithFrame:(CGRect)frame method
and init method.
That way if the imageview is from storyboard the initWithCoder will get called and other methods get called when it is programatically added.
As none of the other answers really worked nor were complete enough I used User Defined Runtime Attributes instead.
To avoid the need to write it in code I added
layer.cornerRadius with Number attribute half the width.
layer.masksToBounds with Bool attribute as YES
Method swizzling is a very good option to achieve this.
Create a UIImageView category class and swizzle initWithCoder: method
#import "UIImageView+MethodSwizzling.h"
#import <objc/runtime.h>
#implementation UIImageView (MethodSwizzling)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = #selector(initWithCoder:);
SEL swizzledSelector = #selector(xxx_initWithCoder:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
// When swizzling a class method, use the following:
// Class class = object_getClass((id)self);
// ...
// Method originalMethod = class_getClassMethod(class, originalSelector);
// Method swizzledMethod = class_getClassMethod(class, swizzledSelector);
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
}
else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
#pragma mark - Method Swizzling
- (id)xxx_initWithCoder:(NSCoder*)aDecoder {
[self xxx_initWithCoder:aDecoder];
self.layer.cornerRadius = self.frame.size.width / 2;
self.layer.masksToBounds = YES;
NSLog(#"xxx_initWithCoder: %#", self);
return self;
}
You don't have to create subclass of UIImageView and do not need to change your object's class everywhere in XIB/Storybord.
Click here to know about method swizzling.
What your "answer" suggests is that you are using UIImageViews in the Storyboard. The best approach would be to create a subclass of UIImageView, e.g.:
//MyImageView.h
#import <UIKit/UIKit.h>
#interface MyImageView : UIImageView
#end
The code to adapt the cornerRadius and the clipsToBounds should be added to the MyImageView.m:
//MyImageView.m
- (id)layoutSubviews {
[super layoutSubviews];
self.layer.cornerRadius = self.view.frame.width.width / 2
self.layer.clipsToBounds = true;
// this line may be only needed in init since the clipsToBounds does not change due to autoLayout.
}
After writing that code, you need to set the class attribute of all UIImageViews in the Storyboard (all those that should be circular) to MyImageView instead of the default UIImageView.
Attempting to simply add in a joystick to control a sprite side to side, and up and down. The only non-outdated tutorial I can find for this, which is still a year old, simply get's me as far as 'Implicit declaration of function 'ccDrawSolidPoly' is invalid in C99'
.m
Code:
- (id)init
{
// Apple recommend assigning self with supers return value
self = [super init];
if (!self) return(nil);
// Enable touch handling on scene node
self.userInteractionEnabled = YES;
[self initJoyStick];
// done
return self;
}
-(void)initJoyStick
{
SneakyJoystickSkinnedBase *leftJoy = [[SneakyJoystickSkinnedBase alloc] init];
[leftJoy setPosition:CGPointMake(64, 32)];
leftJoy.backgroundSprite = [ColoredCircleSprite circleWithColor:[CCColor colorWithRed:255.0 green:0 blue:0 alpha:120.0] radius:32];
leftJoy.thumbSprite = [ColoredCircleSprite circleWithColor:[CCColor colorWithRed:0 green:0 blue:255.0 alpha:200.0] radius:16];
leftJoy.joystick = [[SneakyJoystick alloc] initWithRect:CGRectMake(0, 0, 128, 128)];
joystick = leftJoy.joystick;
[self addChild:joystick];
}
.h Code:
#import "cocos2d.h"
#import "cocos2d-ui.h"
#import "SneakyJoystick.h"
#import "SneakyButton.h"
#import "SneakyButtonSkinnedBase.h"
#import "SneakyJoystickSkinnedBase.h"
#import "ColoredCircleSprite.h"
#import "ColoredSquareSprite.h"
#interface HelloWorldScene : CCScene
{
SneakyJoystick *joystick;
}
+ (HelloWorldScene *)scene;
- (id)init;
#end
Any ideas or other ways of accomplishing this? I would highly appreciate it!
I had a fun time with this also.
The 2 header files ColoredCircleSprite.h and ColoredSquareSprite.h imported cocos2d.h. They also need to import CCDrawingPrimitives.h
This is the only way I could get it to work. Hope this helps.
I am trying to animate a UIView (block-based animation) but I cannot make the timing work (duration, etc.). The animation runs, because the changes are done, and the completition output message is shown, but it just ignores the duration and instantly makes the changes.
I asume there is something wrong with the way I am doing things, but I just cannot figure out where the mistake is. Let me explain what I am trying to do:
I have a UIViewController (viewcontroller) that handles two objects (view1 and view2) of a UIView sublcass in which I have defined the touchesEnded method.
The idea is that when view1 has been touched, I want to animate view2. So what I did was to implement an animation method in the UIView subclass, a notification in the touchesEnded method (also in the UIView subclass), and
a trigger method in the controller that would call the animation of the second view. Something like this:
// In the UIView subclass:
- (void) myAnimation{
[UIView animateWithDuration:2.0
delay:0.0
options: UIViewAnimationCurveEaseOut
animations:^{
self.alpha = 0.5;
}
completion:^(BOOL finished){
NSLog(#"Done!");
}];
}
// In the UIView subclass:
- (void) touchesEnded: (NSSet*) touches withEvent: (UIEvent*) event {
[pParent viewHasBeenTouched]; // pParent is a reference to the controller
}
// In the UIViewController:
- (void) viewHasBeenTouched {
[view2 myAnimation];
}
(The animation and work flow is in fact a bit more complex, but this simple example just fails to work)
If I place the animation somewhere else, it may work, for example just after initializing the views in the init method of the controller. But if I try to do this forward-backward calls, the animation will just ignore the duration and execute in one step.
Any ideas? What have I missed about touches and gestures that I should know? Thank you.
NEW INFORMATION ADDED TO THE ORIGINAL POST:
The AppDelegate does nothing but this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[TestViewController alloc] init];
self.window.rootViewController = self.viewController;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
The TestViewControler.h is just this:
#import <UIKit/UIKit.h>
#import "TestView.h"
#interface TestViewController : UIViewController{
TestView* myView;
}
- (void) viewHasBeenTouched;
#end
and the viewDidLoad only does this:
- (void)viewDidLoad{
[super viewDidLoad];
myView = [[TestView alloc] initWithParent:self];
[self.view addSubview:myView];
}
Finally, the UIView has a TestView.h which looks like this:
#import <UIKit/UIKit.h>
#class TestViewController; // Forward declaration
#interface TestView : UIView{
TestViewController* pParent;
}
- (id)initWithParent:(TestViewController*) parent;
- (void) myAnimation;
#end
And the init method used is:
- (id)initWithParent:(TestViewController *)parent{
CGRect frame = CGRectMake(50, 20, 100, 200);
self = [super initWithFrame:frame];
if (self) pParent = parent;
self.backgroundColor = [UIColor blueColor];
return self;
}
So... with this simple code I posted, the error occurs. As I said, the animation does change the alpha, but with no delay or timing. It's just instantaneous. Any ideas with this added information?
Thank you again for the help.
I found the problem. I want to apologize first for all the people how have studied my problem and have lost valuable time on it.
All the second part I posted in the original question was copy and pasted indeed, it was the first part that had those two mismatching errors because they came from a more complex code. And that code works without problem as you have all stated. The problem is that I did not copy and paste a method that I thought I had removed from the project (and which is called at the start of the application):
- (BOOL)shouldAutorotateToInterfaceOrientation (UIInterfaceOrientation)interfaceOrientation {
// ... More code
[UIView setAnimationsEnabled:NO];
// ... More code
return YES;
}
It obviously needs no further explanation.
Again thank you very much for your time, and my sincere apologizes.
The iPad programming guide says that the splitView's left pane is fixed to 320 points. But 320 pixels for my master view controller is too much. I would like to reduce it and give more space to detail view controller. Is it possible by anyway?
Link to the document which speaks about fixed width.
If you subclass UISplitViewController, you can implement -viewDidLayoutSubviews and adjust the width there. This is clean, no hacks or private APIs, and works even with rotation.
- (void)viewDidLayoutSubviews
{
const CGFloat kMasterViewWidth = 240.0;
UIViewController *masterViewController = [self.viewControllers objectAtIndex:0];
UIViewController *detailViewController = [self.viewControllers objectAtIndex:1];
if (detailViewController.view.frame.origin.x > 0.0) {
// Adjust the width of the master view
CGRect masterViewFrame = masterViewController.view.frame;
CGFloat deltaX = masterViewFrame.size.width - kMasterViewWidth;
masterViewFrame.size.width -= deltaX;
masterViewController.view.frame = masterViewFrame;
// Adjust the width of the detail view
CGRect detailViewFrame = detailViewController.view.frame;
detailViewFrame.origin.x -= deltaX;
detailViewFrame.size.width += deltaX;
detailViewController.view.frame = detailViewFrame;
[masterViewController.view setNeedsLayout];
[detailViewController.view setNeedsLayout];
}
}
In IOS 8.0 you can easily do this by doing the following:
1. In your MasterSplitViewController.h add
#property(nonatomic, assign) CGFloat maximumPrimaryColumnWidth NS_AVAILABLE_IOS(8_0);
2. In your MasterSplitViewController.m viewDidLoad method add
self.maximumPrimaryColumnWidth = 100;
self.splitViewController.maximumPrimaryColumnWidth = self.maximumPrimaryColumnWidth;
This is a really good, simple and easy feature of IOS 8.
this code is work for me
[splitViewController setValue:[NSNumber numberWithFloat:200.0] forKey:#"_masterColumnWidth"];
No.
There are two private properties
#property(access,nonatomic) CGFloat masterColumnWidth;
#property(access,nonatomic) CGFloat leftColumnWidth; // both are the same!
but being private mean they can't be used for AppStore apps.
iOS 8 introduced a new property:
// An animatable property that can be used to adjust the maximum absolute width of the primary view controller in the split view controller.
#property(nonatomic, assign) CGFloat maximumPrimaryColumnWidth NS_AVAILABLE_IOS(8_0); // default: UISplitViewControllerAutomaticDimension
Use this property to adjust your master viewcontroller to your desired width.
Here is how I did this in iOS8 with Swift.
class MainSplitViewController: UISplitViewController {
override func viewDidLoad() {
self.preferredDisplayMode = UISplitViewControllerDisplayMode.AllVisible
self.maximumPrimaryColumnWidth = 100 // specify your width here
}
}
If you need to change the width dynamically from within your master/detail view in the split view, then do something like this:
var splitViewController = self.splitViewController as MainSplitViewController
splitViewController.maximumPrimaryColumnWidth = 400
The storyboard way would be this one, mentioned by #Tim:
Furthermore, if you want the Master view to always take up a certain percentage of the screen then you can use the Key Path = "preferredPrimaryColumnWidthFraction" instead and set the value to 0.2 (for 20% screen size).
Please note that the "maximumPrimaryColumnWidth" is set to 320, so if you try the screen percent value of 0.5 (50%) it won't go above 320. You can add a key path for maximumPrimaryColumnWidth if you need to override this.
None of the answers worked for me on iOS7, so I did some of my own research and created a working solution. This will involve subclassing UISplitViewController for the full functionality.
I will present the answer as if we just created a new project for iPad with all device orientations and have set the custom UISplitViewController as the main view controller.
Create your custom UISplitViewController. In this example mine is called MySplitViewController. All code will be based in MySplitViewController.m.
We're going to need to access a method from the UISplitViewControllerDelegate so add that and set the delegate. We'll also setup a delegate forwarder incase you need to call the delegate methods from another class.
#interface MySplitViewController () <UISplitViewControllerDelegate>
#property (nonatomic, weak) id<UISplitViewControllerDelegate> realDelegate;
#end
#implementation MySplitViewController
- (instancetype)init {
self = [super init];
if (self) {
self.delegate = self;
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
self.delegate = self;
}
return self;
}
- (void)setDelegate:(id<UISplitViewControllerDelegate>)delegate {
[super setDelegate:nil];
self.realDelegate = (delegate != self) ? delegate : nil;
[super setDelegate:delegate ? self : nil];
}
- (BOOL)respondsToSelector:(SEL)aSelector {
id delegate = self.realDelegate;
return [super respondsToSelector:aSelector] || [delegate respondsToSelector:aSelector];
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
id delegate = self.realDelegate;
return [delegate respondsToSelector:aSelector] ? delegate : [super forwardingTargetForSelector:aSelector];
}
Setup the master and detail view controllers.
- (void)viewDidLoad {
[super viewDidLoad];
UIViewController* masterViewController = [[UIViewController alloc] init];
masterViewController.view.backgroundColor = [UIColor yellowColor];
UIViewController* detailViewController = [[UIViewController alloc] init];
detailViewController.view.backgroundColor = [UIColor cyanColor];
self.viewControllers = #[masterViewController, detailViewController];
}
Lets add our desired width to a method for easy reference.
- (CGFloat)desiredWidth {
return 200.0f;
}
We'll manipulate the master view controller before presenting it.
- (void)splitViewController:(UISplitViewController *)svc popoverController:(UIPopoverController *)pc willPresentViewController:(UIViewController *)aViewController {
id realDelegate = self.realDelegate;
if ([realDelegate respondsToSelector:#selector(splitViewController:popoverController:willPresentViewController:)]) {
[realDelegate splitViewController:svc popoverController:pc willPresentViewController:aViewController];
}
CGRect rect = aViewController.view.frame;
rect.size.width = [self desiredWidth];
aViewController.view.frame = rect;
aViewController.view.superview.clipsToBounds = NO;
}
However, now we're left with a display like this.
So were going to override a private method. Yes a private method, it will still be acceptable in the App Store since its not an underscore private method.
- (CGFloat)leftColumnWidth {
return [self desiredWidth];
}
This deals with portrait mode. So a similar thing for -splitViewController:willShowViewController:invalidatingBarButtonItem: and you should be set for landscape.
However none of this will be needed in iOS8. You'll be able to simply call a min and max width property!
use the following code before assigning to the rootviewcontroller. It works for me with ios7
[self.splitViewController setValue:[NSNumber numberWithFloat:256.0] forKey:#"_masterColumnWidth"];
self.window.rootViewController = self.splitViewController;
Since no one mentioned that this can be done from IB, I want to add this answer. Apparently, you can set "User Defined Runtime Attributes" for the UISplitViewContorller with following details:
Key Path:masterColumnWidth
Type: Number
Value: 250
In my case, I had to set both maximum and minimum to make this work
mySplitViewController.preferredDisplayMode = .allVisible;
mySplitViewController.maximumPrimaryColumnWidth = UIScreen.main.bounds.width/2;
mySplitViewController.minimumPrimaryColumnWidth = UIScreen.main.bounds.width/2;
You can use GSSplitViewController. This one will work on iOS 7 and 8
splitView = [[GSSplitViewController alloc] init];
splitView.masterPaneWidth = 180;
You can also include it by adding pod 'GSSplitViewController' to your Podfile.
ViewController.h
#property(nonatomic, assign) CGFloat maximumPrimaryColumnWidth NS_AVAILABLE_IOS(8_0);
ViewController.m
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
if (SYSTEM_VERSION_LESS_THAN(#"10.0")) {
[self setValue:[NSNumber numberWithFloat:200.0]forKey:#"_masterColumnWidth"];
}else{
self.maximumPrimaryColumnWidth = 200;
self.splitViewController.maximumPrimaryColumnWidth = self.maximumPrimaryColumnWidth;
}
Swift 3.0 you use like
let widthfraction = 2.0 //Your desired value for me 2.0
splitViewController?.preferredPrimaryColumnWidthFraction = 0.40
let minimumWidth = min((splitViewController?.view.bounds.size.width)!,(splitViewController?.view.bounds.height)!)
splitViewController?.minimumPrimaryColumnWidth = minimumWidth / widthFraction
splitViewController?.maximumPrimaryColumnWidth = minimumWidth / widthFraction
let leftNavController = splitViewController?.viewControllers.first as! UINavigationController
leftNavController.view.frame = CGRect(x: leftNavController.view.frame.origin.x, y: leftNavController.view.frame.origin.y, width: (minimumWidth / widthFraction), height: leftNavController.view.frame.height)
// in UISplitViewController subclass
// let more space for detail in portrait mode
- (void)viewWillLayoutSubviews
{
CGFloat width;
if (UIInterfaceOrientationIsPortrait(UIApplication.sharedApplication.statusBarOrientation)){
width = CGRectGetWidth(self.view.bounds) * 0.25f;
}
else {
width = CGRectGetWidth(self.view.bounds) * 0.33f;
}
width = (NSInteger)fminf(260, fmaxf(120, width));
self.minimumPrimaryColumnWidth = width;
self.maximumPrimaryColumnWidth = width;
[super viewWillLayoutSubviews];
}
This code work for me:)
#interface UISplitViewController(myExt)
- (void)setNewMasterSize:(float)size;
#end
#implementation UISplitViewController(myExt)
- (void)setNewMasterSize:(float)size
{
_masterColumnWidth = size;
}
#end
and use it on each operation with view (like rotation)