iOS 7 App crashes with custom transitions - ios7

I am trying to add custom transitions to my existing iOS App. It seems to keep crashing. My app has a main navigation controller, which I have sub-classed. Root controller of the navigation controller acts as delegate for the UINavigationController.
PS: I have also tried making the custom navigation controller a delegate of itself but it crashes there before the call to the animationControllerForOperation delegate method.
This is the code that I have
Custom Navigation Controller
#interface MainNavigationViewController : UINavigationController
#end
#implementation MainNavigationViewController
- (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC
{
if ([fromVC isKindOfClass:[FlowLayoutCategoryController class]] && [toVC isKindOfClass:[FlowLayoutCategoryController class]]) {
if (operation == UINavigationControllerOperationPush) {
CategoryTransitionAnimation *animation = [CategoryTransitionAnimation new];
animation.type = TransitionTypePush;
return animation;
}
else if (operation == UINavigationControllerOperationPop) {
CategoryTransitionAnimation *animation = [CategoryTransitionAnimation new];
animation.type = TransitionTypePop;
return animation;
}
else {
return nil;
}
}
return nil;
}
Transition Animation Class
typedef enum
{
TransitionTypePush,
TransitionTypePop
} TransitionType;
#interface CategoryTransitionAnimation : NSObject<UIViewControllerAnimatedTransitioning>
#property (nonatomic, assign) TransitionType type;
#end
#import "CategoryTransitionAnimation.h"
#implementation CategoryTransitionAnimation
#pragma mark - UIViewControllerAnimatedTransitioning
- (void) animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
//Get references to the view hierarchy
UIView *containerView = [transitionContext containerView];
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
if (self.type == TransitionTypePush) {
//Add 'to' view to the hierarchy with 0.0 scale
toViewController.view.transform = CGAffineTransformMakeScale(0.0, 0.0);
[containerView insertSubview:toViewController.view aboveSubview:fromViewController.view];
//Scale the 'to' view to to its final position
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
toViewController.view.transform = CGAffineTransformMakeScale(1.0, 1.0);
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
} else if (self.type == TransitionTypePop) {
//Add 'to' view to the hierarchy
[containerView insertSubview:toViewController.view belowSubview:fromViewController.view];
//Scale the 'from' view down until it disappears
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
fromViewController.view.transform = CGAffineTransformMakeScale(0.0, 0.0);
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
}
- (NSTimeInterval) transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 1.0;
}
#end

I'm going to make a guess that the problem is that you have omitted a step: You are supposed to fetch the finalFrameForViewController: for the "to" view controller and set the view's frame to that. Just a guess, but I can't help noticing that you are not giving the view any frame, which can't be good.

Related

popup can't close (IBAction not working)

I use a popup system that I found here : https://blog.typpz.com/2013/12/09/ios-sdk-create-a-pop-up-window/
And after following the guide step by step everything works except the closing button. I tried to link it in various ways but nothing works.
Does anyone know what I do wrong ?
here is my code:
PopUpController.h:
#import <UIKit/UIKit.h>
//#import <QuartzCore/QuartzCore.h>
#import "AppDelegate.h"
#interface PopUpViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIView *popUpView;
- (void)showInView:(UIView *)aView animated:(BOOL)animated;
- (IBAction)closePopup:(id)sender;
#end
PopUpController.m:
#import "PopUpViewController.h"
#interface PopUpViewController ()
#end
#implementation PopUpViewController
- (void)viewDidLoad {
self.view.backgroundColor=[[UIColor blackColor] colorWithAlphaComponent:.6];
self.popUpView.layer.cornerRadius = 5;
self.popUpView.layer.shadowOpacity = 0.8;
self.popUpView.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
self.popUpView.clipsToBounds = YES;
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma animation
- (void)showAnimate
{
self.view.transform = CGAffineTransformMakeScale(1.3, 1.3);
self.view.alpha = 0;
[UIView animateWithDuration:.25 animations:^{
self.view.alpha = 1;
self.view.transform = CGAffineTransformMakeScale(1, 1);
}];
}
- (void)removeAnimate
{
[UIView animateWithDuration:.25 animations:^{
self.view.transform = CGAffineTransformMakeScale(1.3, 1.3);
self.view.alpha = 0.0;
} completion:^(BOOL finished) {
if (finished) {
[self.view removeFromSuperview];
}
}];
}
- (void)showInView:(UIView *)aView animated:(BOOL)animated
{
[aView addSubview:self.view];
if (animated) {
[self showAnimate];
}
}
- (IBAction)closePopup:(id)sender {
NSLog(#"closing...");
[self removeAnimate];
}
#end
NOTE: I don't even get the NSLog closing... on my console when I click the closing button
here is a screenshot of my .xib file:
Thank you for your response.

ios7 - how to transition back to self

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

Working with a container view

This is my situation. I have a viewController. With at the top three buttons and below the buttons a containerview. When you push a button, the container view should change.
This is what I have done in storyboard.
Dragged a view controller into my storyboard. added 3 buttons and a containerview into it.
This view controller is off class viewController
Dragged a second viewcontroller into it. And controlled dragged from the containerView to this view controller. and selected embed segue.
Now in code I do the following for controller viewController
-(IBAction)chooseFirstController:(id)sender {
[self.childViewControllers.lastObject switchToFirst];
}
-(IBAction)chooseSecondController:(id)sender {
[self.childViewControllers.lastObject switchToSecond];
}
-(IBAction)chooseThirdController:(id)sender {
[self.childViewControllers.lastObject switchToThird];
}
And for my containerController.h I do the following.
#interface ContainerViewController : ViewController
#property (nonatomic,strong) FirstController *cont1;
#property (nonatomic,strong) SecondController *cont2;
#property (nonatomic,strong) ThirdController *cont3;
#property (nonatomic,strong) ContainerViewController *currentController;
And in my container.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.cont1 = [[FirstController alloc]initWithNibName:#"FirstController" bundle:nil];
self.cont2 = [[SecondController alloc]initWithNibName:#"SecondController" bundle:nil];
self.cont3 = [[ThirdController alloc]initWithNibName:#"ThirdViewController" bundle:nil];
[self addChildViewController:self.cont1];
self.currentController = self.cont1;
[self.view addSubview:self.cont1.view];
}
-(void)switchToFirst {
if (self.currentController != self.cont1) {
[self addChildViewController:self.cont1];
[self moveToNewController:self.cont1];
}
}
-(void)switchToSecond {
if (self.currentController != self.cont2) {
[self addChildViewController:self.cont2];
[self moveToNewController:self.cont2];
}
}
-(void)switchToThird {
if (self.currentController != self.cont3) {
[self addChildViewController:self.cont3];
[self moveToNewController:self.cont3];
}
}
-(void)moveToNewController:(id) newController {
[self.currentController willMoveToParentViewController:nil];
[self transitionFromViewController:self.currentController toViewController:newController duration:.6 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{}
completion:^(BOOL finished) {
[self.currentController removeFromParentViewController];
[newController didMoveToParentViewController:self];
self.currentController = newController;
}];
}
But I keep getting error "No known instance method for selector switchtoFirst" in my IBActions.
Can anybody help me?
Thanks in advance.
I would guess that lastObject is returning a UIViewController and doesn't know it's a ContainerViewController - hence doesn't know about the switchtoFirst method.
Try something like:
-(IBAction)chooseFirstController:(id)sender {
UIViewController *vc = self.childViewControllers.lastObject;
if([vc isKindOfClass:[ContainerViewController class]]) {
ContainerViewController *containerVC = (ContainerViewController *)vc;
[containerVC switchtoFirst];
}
}

Tint a UIView with all its subviews

Any way you can tint a UIView? Not the background color, but the entire UIView with all its subviews.
e.g - A UIView with an animation of a star rotating , i.e The UIView shape is constantly changing.
Eventually I created a UIView category that enables tinting of a UIView,
without filling the UIView rectangle, here it is :
Takes an image representation of the UIView, then colors it in the
given UIColor, this category was created to replicate a UIButton
default highlight behavior, so it also comes with a method that can activate that
behavior and let the category handle all touch methods.
//------------------ .h Interface file ------- //
//
// UIView UIView_Tint.h
// BabyQA
//
// Created by yogev shelly on 8/10/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#define tintColorClassicUIButton [UIColor colorWithWhite:0.0 alpha:0.5]
#interface UIView(Tint)
//proprties should not be used, use the methods decalred bellow
#property (nonatomic,retain) UIColor* tintColor;
#property(nonatomic,retain) UIImageView* tintImageView;
#property(nonatomic,assign) BOOL tintOnTouchActive;
-(void)tintToColor:(UIColor*)color;
-(void)clearTint;
-(void)enableTintOnTouchWithColor:(UIColor*)color;
-(void)disableTintOnTouch;
-(UIImage *)imageRepresentation;
-(UIImage*)imageRepresentationWithTintColor:(UIColor*)color;
#end
//------------------ .m Implementation file ------- //
// UIView UIView_Tint.m
// BabyQA
//
// Created by yogev shelly on 8/10/12.
// Copyright (c) 2012 __MyCompanyName__. All rights not reserved - go wild!
//
#import "UIView Tint.h"
#import <objc/runtime.h>
#import <QuartzCore/QuartzCore.h>
static char const * const tintImageViewKey = "tintImageView";
static char const * const tintColorKey = "tintColorKey";
static char const * const tintOnTouchActiveKey = "tintOnTouchActive";
#implementation UIView (Tint)
#dynamic tintImageView;
#dynamic tintColor;
#dynamic tintOnTouchActive;
-(void)enableTintOnTouchWithColor:(UIColor*)color
{
self.tintColor = color;
self.tintOnTouchActive = TRUE;
}
-(void)disableTintOnTouch
{
self.tintOnTouchActive = FALSE;
}
-(void)tintToColor:(UIColor*)color
{
if(![self.tintColor isEqual:color] || !self.tintImageView)
{
self.tintColor = color;
UIImage* tintImage = [self imageRepresentationWithTintColor:self.tintColor];
self.tintImageView = [[[UIImageView alloc] initWithImage:tintImage] autorelease];
}
[self addSubview:self.tintImageView];
}
-(void)clearTint
{
[self.tintImageView removeFromSuperview];
}
-(void)clearTintWithSecondsDelay:(float)delay
{
[self performSelector:#selector(clearTint) withObject:self afterDelay:delay];
}
#pragma mark - TouchToggling
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
if(self.tintOnTouchActive)
[self tintToColor:self.tintColor];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
if(self.tintOnTouchActive)
[self clearTintWithSecondsDelay:0.05];
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
if(self.tintOnTouchActive)
[self clearTintWithSecondsDelay:0.05];
}
#pragma mark - TintingPart
-(UIImage *)imageRepresentation
{
UIGraphicsBeginImageContext(self.bounds.size);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
-(UIImage*)imageRepresentationWithTintColor:(UIColor*)color
{
UIImage* viewImage = [self imageRepresentation];
viewImage = [self tintedImage:viewImage UsingColor:color];
return viewImage;
}
-(UIImage *)tintedImage:(UIImage*)image UsingColor:(UIColor *)tintColor {
UIGraphicsBeginImageContextWithOptions(image.size, NO, [[UIScreen mainScreen] scale]);
CGRect drawRect = CGRectMake(0, 0, image.size.width, image.size.height);
[image drawInRect:drawRect];
[tintColor set];
UIRectFillUsingBlendMode(drawRect, kCGBlendModeSourceAtop);
UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return tintedImage;
}
#pragma mark - Dynamic setters/getters for Associative References
-(void)setTintImageView:(UIImageView *)tintImageView
{
objc_setAssociatedObject(self, tintImageViewKey, tintImageView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(UIImageView*)tintImageView
{
return objc_getAssociatedObject(self , tintImageViewKey);
}
-(UIColor*)tintColor
{
return objc_getAssociatedObject(self , tintColorKey);
}
-(void)setTintColor:(UIColor *)tintColor
{
objc_setAssociatedObject(self, tintColorKey, tintColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(BOOL)tintOnTouchActive
{
return [objc_getAssociatedObject(self, tintOnTouchActiveKey) boolValue];
}
-(void)setTintOnTouchActive:(BOOL)tintOnTouchActive
{
objc_setAssociatedObject(self, tintOnTouchActiveKey, [NSNumber numberWithBool:tintOnTouchActive], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
To tint a UIView, add another subview on top of it with the same frame and an alpha transparency set.
For example let's say your container type view is called containerView, you'd do as follows:
CGRect overlayFrame = containerView.frame;
UIView *overlayView = [UIView alloc] initWithFrame:overlayFrame];
overlayView.alpha = 0.5f;
overlayView.color = [UIColor blackColor];
[containerView addSubview:overlayView];
This gives you a semi transparent (0.5f) black tint that will give a tint like appearance to all the subviews underneath.

UISplitViewController stops auto-rotating after trying to use the UINavigationController inside of it

I've been having a bit of trouble with a UISplitViewController in my iPad app. I am attempting to make a simple navigation tree using the UINavigationController inside of the UISplitView. I have used the following basic code to do this:
NavController.h
#interface NavController : NSObject {
/*
* This is connected properly to the UINavigationController in the
* UISplitViewController through Interface Builder.
*/
UINavigationController *navigationController;
}
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#end
NavController.m
#import "NavController.h"
#implementation NavController
#synthesize navigationController;
- (void) awakeFromNib {
UIViewController *testController = [[UIViewController alloc] init];
UITableView *tableView = [[UITableView alloc] init];
[testController setView: tableView];
[navigationController pushViewController: testViewController
animated: YES];
}
#end
This code successfully pushes the view to the navigation controller, and I can navigate back with the back button, however, my problem arises with the fact that after this happens, my UISplitViewController no longer auto-rotates or rotates at all from the portrait position. When I remove this code (and the view does not get pushed) it works as expected.
What am I doing wrong, and am I going about this in the right way?
This drove me absolutely nuts too. I did a couple of things that made it work, but I'm not happy about my solutions -- 1) I don't really understand it and 2) it seems hacky.
I added this to my app delegate (my .m file):
#interface UITabBarController (MyApp)
#end
#interface UINavigationController (MyApp)
#end
#implementation UITabBarController (MyApp)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return YES;
}
#end
#implementation UINavigationController (MyApp)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return YES;
}
#end
This worked for the most part. For the views that didn't auto-rotate though, I had to manually rotate the views myself using transforms. I did something like:
- (void)deviceOrientationDidChangeWithAnimation:(BOOL)animated {
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (orientation == oldOrientation) {
return;
}
if (animated) {
CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
[UIView setAnimationDidStopSelector:#selector(orientationChanged)];
}
[self sizeToFitOrientation:YES];
if (animated) {
[UIView commitAnimations];
}
oldOrientation = orientation;
}
- (CGAffineTransform)transformForOrientation {
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (orientation == UIInterfaceOrientationLandscapeLeft) {
return CGAffineTransformMakeRotation(M_PI*1.5); // rotated CCW
} else if (orientation == UIInterfaceOrientationLandscapeRight) { // CW
return CGAffineTransformMakeRotation(M_PI/2);
} else if (orientation == UIInterfaceOrientationPortraitUpsideDown) { // CCW
return CGAffineTransformMakeRotation(-M_PI);
} else { // CW
return CGAffineTransformIdentity;
}
}
- (void)sizeToFitOrientation:(BOOL)transform {
if (transform) {
self.view.transform = CGAffineTransformIdentity;
}
CGRect frame = [UIScreen mainScreen].applicationFrame;
CGPoint center = CGPointMake(frame.origin.x + ceil(frame.size.width/2), frame.origin.y + ceil(frame.size.height/2));
CGFloat width = frame.size.width - 0 * 2;
CGFloat height = frame.size.height - 0 * 2;
UIInterfaceOrientation _orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UIInterfaceOrientationIsLandscape(_orientation)) {
self.view.frame = CGRectMake(0, 0, height, width);
} else {
self.view.frame = CGRectMake(0, 0, width, height);
}
self.view.center = center;
if (transform) {
self.view.transform = [self transformForOrientation];
}
}
Hope this helps! And if someone can point out mistakes I've made (or bad things I'm perpetuating), I'd be happy to learn. :)