Custom UIStoryboardSegue - ios

I'm writing a custom UIStoryboardSegue to animate the transitions between views. When a segue is triggered, each controller (source and destination) is asked to animate accordingly. Here's how:
- (void)perform
{
UIViewController * sourceViewController = [self sourceViewController];
UIViewController * destinationViewController = [self destinationViewController];
UIViewController * containerViewController = [self containerViewController];
UIView * sourceView = sourceViewController.view;
UIView * destinationView = destinationViewController.view;
UIView * containerView = containerViewController.view;
// The container view is as large as the union of the two other views
CGRect sourceFrame = sourceView.frame;
CGRect destinationFrame = destinationView.frame;
CGRect containerFrame = CGRectUnion(sourceFrame, destinationFrame);
[containerView setFrame:containerFrame];
// The two views are presented in a container view; this way no one fights about who gets what
[sourceView removeFromSuperview];
[containerView addSubview:sourceView];
[containerView addSubview:destinationView];
// [sourceViewController presentViewController:containerViewController animated:NO completion:^{
// NSLog(#"done presenting");
// }];
// NSLog(#"done calling presenting");
id <HyTransition> presentingTransition = [self presentingTransitionForViewController:destinationViewController];
id <HyTransition> dismissingTransition = [self dismissingTransitionForViewController:sourceViewController];
// Perform the transitions
[presentingTransition performWithTransitionContext:self.presentingContext];
[dismissingTransition performWithTransitionContext:self.dismissingContext];
}
The problem is when presenting the containing view. It works well if the source view controller is a standard view controller, but not if it's UINavigationController or others of the kind, which don't add their views to the view hierarchy. When doing so, I get this:
Warning: Attempt to present <HyPresentationViewController: 0x7fdac2d34b60> on <HyRootController: 0x7fdac2e28590> whose view is not in the window hierarchy!
How can I present the containing view?
Edit: notice that I do not require a containing view controller - a containing view is enough.

Related

UIViewController within UIViewControllers

I have a UIViewController that has UITabBar in it. I am trying to imitate a UITabBarController.
My question is how do I set or a UIViewController whenever a TabBarItem is selected?
I am confused as to how to put a UIViewController inside my UIViewController that is trying to imitate a UITabBarController.
Please don't ask me to use a UITabBarController
You can use child view controllers to embed view controllers in other view controllers, just call this from your view controller:
YourViewController *childViewController = [[YourViewController alloc] init];
UIView *containerView = //some view in your view hierarchy
childViewController.view.frame = containerView.bounds;
[self addChildViewController: childViewController];
[containerView addSubview:childViewController.view];
[childViewController didMoveToParentViewController:self];
If you want to page between child view controllers, you can use a UIPageViewController as the root child view controller or alternatively borrow this code from the apple documentation:
- (void) cycleFromViewController: (UIViewController*) oldC
toViewController: (UIViewController*) newC {
[oldC willMoveToParentViewController:nil]; // 1
[self addChildViewController:newC];
newC.view.frame = [self newViewStartFrame]; // 2
CGRect endFrame = [self oldViewEndFrame];
[self transitionFromViewController: oldC toViewController: newC // 3
duration: 0.25 options:0
animations:^{
newC.view.frame = oldC.view.frame; // 4
oldC.view.frame = endFrame;
}
completion:^(BOOL finished) {
[oldC removeFromParentViewController]; // 5
[newC didMoveToParentViewController:self];
}];
}
(1) To learn it in detail, I would suggest you to go through:
Creating Custom Container View Controllers - https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html#//apple_ref/doc/uid/TP40007457-CH18-SW6
And
WWDC 2011 Session Video - Session 102 - Implementing UIViewController Containment.
(2) For quick learning, go through: Using Multiple ViewControllers on a Single Screen in iOS
Demo project at git: multiple-viewcontrollers

Navigation bar is removed when pushing a viewcontroller from another storyboard

I have many storyboards in my project to have modules with specific functionalities. In one of my storyboard, I have a navigation controller, which push the initial view controller of another storyboard. When I push it, the navigation bar is removed and there is no way to get this specific bar back. When I put another navigation controller in my new storyboard, the navigation bar is resetted with an ugly transition (it comes from the right and replace the older one).
This is how I push my new storyboard's view controller :
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:aStoryboardName bundle:nil];
UIViewController *SideBarInitialViewController = [storyboard instantiateInitialViewController];
UIStoryboardSegue *segue = [[GDFromRightCustomSegue alloc] initWithIdentifier:aSegueIdentifier source:aSource destination:SideBarInitialViewController];
[segue perform];
I perform a custom segue as well to get rid of the basic animation (the view coming from below) :
UIView *sourceView = [self.sourceViewController view];
UIView *destinationView = [self.destinationViewController view];
CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height;
CGFloat screenWidth = [[UIScreen mainScreen] bounds].size.width;
destinationView.frame = CGRectMake(screenWidth, 0.0, screenWidth, screenHeight);
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
[window insertSubview:destinationView aboveSubview:sourceView];
[UIView animateWithDuration:0.4 animations:^{
destinationView.frame = CGRectOffset(destinationView.frame, -screenWidth, 0.0);
sourceView.frame = CGRectOffset(sourceView.frame, -screenWidth, 0.0);
} completion:^(BOOL finished){
[self.sourceViewController presentViewController:self.destinationViewController animated:false completion:nil];
}];
Is there a way to push the new storyboard without animate the navigation bar, or even better, to have the older navigation controller in my new storyboard ?
In your source storyboard drag a new UIViewController and then drag a ** Modal segue** to this new UIViewController from your source ViewController. Click on this segue and then in the attributes Inspector add a Identifier of segue (let say "newSegue") Identifier must be unique. Also set segue type to "Custom " and write "newSegue" in Segue Class
Now add a catagory on UIStoryBoardSegue with name newSegue and in the .m file write these two methods.
- (id) initWithIdentifier:(NSString *)identifier
source:(UIViewController *)source
destination:(UIViewController *)destination
{
return [super initWithIdentifier:identifier
source:source
destination:[[UIStoryboard storyboardWithName:#"YourDestinationStoryBoardName" bundle:nil] instantiateInitialViewController ]];
}
- (void)perform
{
UIViewController *source = (UIViewController *)self.sourceViewController;
[source presentViewController:self.destinationViewController
animated:YES
completion:Nil];
}
Now in your source ViewController when you want to presenth new View Controller write this line
[self performSegueWithIdentifier:#"newSegue" sender:nil];
Must Remember to replace "YourDestinationStoryBoardName" with your actual destination StoryBoard name in the above function.
Try this Hope this will work fine.

add UIViewController in subview

I don't know if this is the right key to search "add UIViewController in subview".
As what you can see in my image ,there are two ViewController, the main and the second controller. Inside the main controller there is a UIView(blue background color). Inside in UIView, I want to add the second ViewController in my UIView. I have this code but It didn't work.
here's my code
#import "ViewController.h"
#import "SampleViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIView *testView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
SampleViewController * sample = [[SampleViewController alloc] initWithNibName:#"SampleViewController" bundle:nil];
sample.view.frame = CGRectMake(0, 0, self.testView.bounds.size.width, self.testView.bounds.size.height);
[self.testView addSubview:sample.view];
}
#end
I want to know if this is possible? I know initWithNibName: works in xib file, I don't the exact term to search in google about this. I'm just trying to experiment something if this is possible in IOS. Hoping you understand what I'm trying to do. Hoping for your advice. Thanks in advance
here's my update
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIView *testView;
#property(strong,nonatomic) SampleViewController * samples;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIStoryboard *storyBoard = self.storyboard;
SampleViewController * sample = [storyBoard instantiateViewControllerWithIdentifier:#"SampleViewController"];
// SampleViewController * sample = [[SampleViewController alloc] //initWithNibName:#"SampleViewController" bundle:nil];
[self displayContentController:sample];
//commented the below line because it is not needed here, use it when you want to remove
//child view from parent.
//[self hideContentController:sample];
}
- (void) displayContentController: (UIViewController*) content;
{
[self addChildViewController:content]; // 1
content.view.bounds = self.testView.bounds; //2
[self.testView addSubview:content.view];
[content didMoveToParentViewController:self]; // 3
}
- (void) hideContentController: (UIViewController*) content
{
[content willMoveToParentViewController:nil]; // 1
[content.view removeFromSuperview]; // 2
[content removeFromParentViewController]; // 3
}
I always get this error
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </Users/ace/Library/Developer/CoreSimulator/Devices/035D6DD6-B6A5-4213-9FCA-ECE06ED837EC/data/Containers/Bundle/Application/EB07DD14-A6FF-4CF5-A369-45D6DBD7C0ED/Addsubviewcontroller.app> (loaded)' with name 'SampleViewController''
I think, its looking for a nib. I didn't implement a nib here.
You should use Child containment concept, here MainViewController is a parent view controller and you want to add child view controller view as a subview on Main View Controller.
Adding and Removing a Child
//call displayContentController to add SampleViewCOntroller view to mainViewcontroller
[self displayContentController:sampleVCObject];
// write this method in MainViewController
- (void) displayContentController: (UIViewController*) content;
{
[self addChildViewController:content]; // 1
content.view.bounds = testView.bounds; //2
[testView addSubview:content.view];
[content didMoveToParentViewController:self]; // 3
}
Here’s what the code does:
It calls the container’s addChildViewController: method to add the child. Calling the addChildViewController: method also calls the child’s willMoveToParentViewController: method automatically.
It accesses the child’s view property to retrieve the view and adds it to its own view hierarchy. The container sets the child’s size and position before adding the view; containers always choose where the child’s content appears. Although this example does this by explicitly setting the frame, you could also use layout constraints to determine the view’s position.
It explicitly calls the child’s didMoveToParentViewController: method to signal that the operation is complete.
//you can also write this method in MainViewController to remove the child VC you added before.
- (void) hideContentController: (UIViewController*) content
{
[content willMoveToParentViewController:nil]; // 1
[content.view removeFromSuperview]; // 2
[content removeFromParentViewController]; // 3
}
For more details, please refer to apple doc:
https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html
Configuring a Container in Interface Builder, for those who don't want to write code.
To create a parent-child container relationship at design time, add a container view object to your storyboard scene, as shown in Figure 5-3. A container view object is a placeholder object that represents the contents of a child view controller. Use that view to size and position the child’s root view in relation to the other views in the container.
When you load a view controller with one or more container views, Interface Builder also loads the child view controllers associated with those views. The children must be instantiated at the same time as the parent so that the appropriate parent-child relationships can be created.
You can do this simply by using StoryBoards
Open storyboards and select the view controller in which your Blue view is present, open Utilities search for ContainerView and drag it into your blue view, this will automatically adds an view controller that acts as child view for your view. You can resize your container view in size inspector.
I've resolved the problem about the uiview on second uiviewcontroller.
Follow the code that I've used:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SecondViewController *sb = (SecondViewController *)[storyboard instantiateViewControllerWithIdentifier:#"sb"];
sb.view.backgroundColor = [UIColor redColor];
[sb willMoveToParentViewController:self];
[self.view addSubview:sb.view];
[self addChildViewController:sb];
[sb didMoveToParentViewController:self];
I hope to help you.
Thanks a lot
SampleViewController * sample = [[SampleViewController alloc] initWithNibName:#"SampleViewController" bundle:nil];
sample.view.frame = CGRectMake(0, 0, self.testView.bounds.size.width, self.testView.bounds.size.height);
[self addChildViewController:sample];
[self.testView addSubview:sample.view];
You can add a childViewController to UIViewController since iOS5..
it is a great way to maker smaller, more reusable viewControllers, I also really like it.
you're really close, but you just need a couple more lines of code..
///
[self addChildViewController:sample];
[self.testView addSubview:sample.view]; //you already have this..
[sample didMoveToParentViewController:self];
In you viewWillDisappear: or one of the other teardown methods you'll need to clean up like this:
//we'll need another pointer to sample, make it an iVar / property..
[sample willMoveToParentViewController:nil]; // 1
[sample removeFromSuperview]; // 2
[sample removeFromParentViewController]; // 3
You can read the Apple docs on containing child viewControllers here https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html
I'm tring to adding UIViewController in subview, and this work.
On UIViewController I've added 2 button, in .h file:
-(IBAction)matchButtonAction:(id)sender;
-(IBAction)closeButtonAction:(id)sender;
And in .m file:
-(IBAction)matchButtonAction:(id)sender
{
NSLog(#"matchButtonAction");
}
-(IBAction)closeButtonAction:(id)sender
{
NSLog(#"closeButtonAction");
}
but I don't see the log.
I need to add same parameter on UIViewController instantiateViewControllerWithIdentifier?
How to resolve the problem?
My UIViewController initialization is:
AlertDialogViewController *alertDialogView = (AlertDialogViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"alertDialogView"];
[alertDialogView willMoveToParentViewController:self];
[viewController.view addSubview:alertDialogView.view];
[viewController addChildViewController:alertDialogView];
[alertDialogView didMoveToParentViewController:viewController];
Since your view controller is in storyboard you should use instantiateViewControllerWithIdentifier to get the VC from storyboard.
SampleViewController * sample = [self.storyboard instantiateViewControllerWithIdentifier:#"IdOfSampleViewController"];
sample.view.frame = CGRectMake(0, 0, self.testView.bounds.size.width, self.testView.bounds.size.height);
[self.testView addSubview:sample.view];
Don't forget the add the identifier for the SampleViewController in storyboard
I've try to use this code:
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:nil bundle:nil];
secondViewController.view.frame = CGRectMake(0, 0, self.mySubView.bounds.size.width, self.mySubView.bounds.size.height);
[self addChildViewController:secondViewController];
[self.viewDialogSolution addSubview:secondViewController.view];
but I see only myview not the layout of secondViewController.
Ho to resolve the probleam?
Thanks a lot
let controller:SecondViewController =
self.storyboard!.instantiateViewController(withIdentifier: "secondViewController") as!
SecondViewController
controller.view.frame = self.view.bounds
controller.willMove(toParent: self)
self.view.addSubview(controller.view)
self.addChild(controller)
controller.didMove(toParent: self)

Custom Segue Animation Flicker

I am building an application using UISplitViewController as my root view controller (as prescribed by Apple). However, I needed a custom view for login / management to be displayed prior to the UISplitViewController, so I created a custom UIStoryboardSegue that calls some custom animations. I am attempting to recreate the push / pop segues through a modal segue, without actually pushing an popping view controllers. I've implemented everything correctly, however, at the end of my animation I have a flicker. Here is a gif of it:
Here is my custom Segue's code:
- (void)perform {
UIViewController *srcViewController = (UIViewController *) self.sourceViewController;
UIViewController *destViewController = self.destinationViewController;
UIView *prevView = srcViewController.view;
UIView *destView = destViewController.view;
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[window insertSubview:destView aboveSubview:prevView];
[destView enterRight:0.1 then:^{
[destView removeFromSuperview];
[srcViewController.presentingViewController dismissViewControllerAnimated: NO completion:nil];
}];
}
And here is my custom animation (Implemented as a category on UIView):
-(void)enterRight:(float)delay then:(void(^)(void))after
{
CGPoint moveTo = self.center;
CGPoint moveFrom = self.center;
// Grab a point from off the screen
CGFloat simpleOffscreen = [UIScreen mainScreen].bounds.size.width;
// come from off the right side (+)
moveFrom.x = moveFrom.x + simpleOffscreen;
self.center = moveFrom;
self.hidden = NO;
[UIView animateWithDuration:0.5
delay:delay
usingSpringWithDamping:1
initialSpringVelocity:0.1
options:UIViewAnimationOptionCurveEaseIn
animations:^
{
self.center = moveTo;
}
completion:^(BOOL finished)
{
if (after) after();
}
];
}
As you can see in the Segue, I am animating the view into the current view controller, then without animation presenting the actual destination view controller. I think this is where the flicker is introduced, yet I am unsure about how to go about preventing this.
My Storyboard for this custom segue is
Anyone know how to implement this?

IOS Custom sliding UIViewcontroller from left to right and caused segue error

Due to I have to slide UIViewController from left to right by a finger swipe, I have created a custom uiviewcontroller transition, after slide and clicked the navigation inside the destination controller, error occurred.
Terminating app due to uncaught exception 'NSGenericException',
reason: 'Could not find a navigation controller for segue 'stepsPage'.
Push segues can only be used when the source controller is managed by
an instance of UINavigationController.'
- (void) returnHome
{
UIStoryboard *storyboard = self.storyboard;
MainViewController *destVC = [storyboard instantiateViewControllerWithIdentifier:#"main"];
// Get the views.
UIView * toView = destVC.view;
UIView * fromView = self.view;
// Get the size of the view area.
CGRect viewSize = fromView.frame;
// Add the toView to the fromView
[fromView.superview addSubview:toView];
// Position it off screen.
toView.frame = CGRectMake( -320 , viewSize.origin.y, 320, viewSize.size.height);
NSLog(#" viewSize.origin.y %f", viewSize.size.height);
[UIView animateWithDuration:0.3 animations:
^{
// Animate the views on and off the screen. This will appear to slide.
fromView.frame =CGRectMake( 320 , viewSize.origin.y, 320, viewSize.size.height);
toView.frame =CGRectMake(0, viewSize.origin.y, 320, viewSize.size.height);
}
completion:^(BOOL finished)
{
if (finished)
{
// Remove the old view from its parent.
[fromView removeFromSuperview];
//I use it to have navigationnBar and TabBar at the same time
//self.tabBarController.selectedIndex = indexPath.row+1;
}
}];
NSLog(#"swipe");
}
Segue Function in the destination view controller
- (void) prepareForSegue: (UIStoryboardSegue *) segue sender: (id) sender
{
GeneralViewController *GeneralView = (GeneralViewController*)segue.destinationViewController;
NSString *titleString;
// Set the photo if it navigates to the PhotoView
if ([segue.identifier isEqualToString:#"stepsPage"])
{
titleString = #"Steps";
GeneralView.goalStr = [NSString stringWithFormat:#"%d", [mySetting integerForKey:#"dailyStep"]];
GeneralView.currentStr = [NSString stringWithString:_stepLabel.text];
GeneralView.percentage = grpPercent.step;
}
else
{
return;
}
}
Error you are getting you dont have Naviation Controller around controller through which you want to push it to next controller
Below approaches can be applied to such situation
Approach 1 - Visually add Navigation Controller
You need to your first controller or your existing controller must be embedded in UINavigation
controller - you can do it in xcode 5 by going to Editor -> EmbedIn -> Select Navigation Controller
If you dont want Navigation to appear in your app you can use below line
self.navigationController.navigationBar.hidden =YES;
Approach 2 - Programatically add Navigation Controller
if you want to do it programatically you can do it as follows
MainViewController *destVC = [storyboard instantiateViewControllerWithIdentifier:#"main"];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:destVC];

Resources