scrollview with multiple UIViewController - iphone

I'm trying to figure out the best way to implement multiple UIViewControllers within a UIScrollView. For now, I initiate my UIViewController manually and add it as a Subview to Scrollview. This works fine, but the scrollview doesn't show more than ONE UIViewController even after scrolling to the right. Any idea why this might happen? Here's my code:
DTArticle *article = [self.articles objectAtIndex:0];
DTArticle *article2 = [self.articles objectAtIndex:1];
UIStoryboard *mainStoryBoard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
DTArticleViewController *controller = [mainStoryBoard instantiateViewControllerWithIdentifier:#"DTArticleViewController"];
DTArticleViewController *controller2 = [mainStoryBoard instantiateViewControllerWithIdentifier:#"DTArticleViewController"];
controller.article = article;
controller2.article = article2;
[self.parentScrollView addSubview:controller.view];
[self.parentScrollView addSubview:controller2.view];
self.parentScrollView.contentSize = CGSizeMake(self.parentScrollView.frame.size.width
* 2, self.parentScrollView.frame.size.height);
self.parentScrollView.showsHorizontalScrollIndicator = YES;
[self.parentScrollView setPagingEnabled:YES];
[self.view addSubview:self.parentScrollView];

From the code you've added, both views are at the same location, one on top of the other. When you add the second view you should change its frame origin to position it next to the first view.

Related

ScrollView won't scroll after adding as subview

So i'm adding UIView with UIScrollView in it to another view by pressing segment tool:
UIView.h
#interface gettingELORolesViewController : UIViewController{
UIViewController *currentController;
NSMutableArray *viewControllers;
}
- (IBAction)SegmentToggle:(UISegmentedControl *)sender;
#property (strong, nonatomic) IBOutlet UIView *containerView;
UIView.m
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Storyboard_iPhone"
bundle:nil];
firstView *FirstView = [sb instantiateViewControllerWithIdentifier:#"firstOne"];
secondView *SecondView = [sb instantiateViewControllerWithIdentifier:#"secondOne"];
viewControllers = [NSMutableArray arrayWithObjects:FirstView,SecondView,nil];
currentController = FirstView;
[containerView addSubview:FirstView.view];//containerView = self.view
and then depends on what segment is chosen, it shows different view:
- (IBAction)SegmentToggle:(UISegmentedControl *)sender {
UIViewController *selectedView=nil;
if (sender.selectedSegmentIndex==0) {
selectedView= [viewControllers objectAtIndex:0]; // retrieve object at index 0 from viewControllers array
}
else if(sender.selectedSegmentIndex==1){
selectedView= [viewControllers objectAtIndex:1]; // retrieve object at index 1 from viewControllers array
}
[currentController.view removeFromSuperview]; // remove Current displaying view from superView
currentController=selectedView; // make selected View to be the current View
[containerView addSubview:selectedView.view]; // Add newly selected view on container View
}
secondView is tableViewController and everything is working great when i choose second segment. When i choose first one it shows up but scroll doesn't work and i don't know why.
firstView.m viewDidLoad method looks like this:
-(void)viewDidLoad{
[super viewDidLoad];
mainScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
[mainScrollView setContentSize:CGSizeMake(320, 600)];
[mainScrollView setScrollEnabled:YES];
}
Paging is enabled in storyBoard. And it hooked up with .h file of firstView.
Please tell me what am i doing wrong.
When you call -SegmentToggle:,
you create a local variable called selectedView
you assign a view controller to selectedView depending on what segment is selected
the method ends, selectedView goes out of scope
In short, you're not doing anything. You should, at least, replace a view in the current view hierarchy with the view of the selected controller (and maybe stash a reference to the selected controller in an instance variable for later lookup?)
But taking a step back, it looks like you're trying to create a view controller that manages other view controllers. There are now very specific rules around that as of iOS 5. Please watch the WWDC 2011 video called "Implementing UIViewController Containment" for more information and examples.

Multiple ViewControllers onscreen

I would like to place two UIViewControllers on a window (like you can see below). Is it possible to set this up to each view is controlled by it's own controller respectively?
In the app delegate I'm adding the subview the following way
TabBarViewController *tabBarVC = [[TabBarViewController alloc] init];
CGRect frame = tabBarVC.view.frame;
frame.origin.y = self.window.bounds.size.height - frame.size.height;
tabBarVC.view.frame = frame;
[self.window insertSubview:tabBarVC.view aboveSubview:tabVC.view];
It loads, but when I click on a button (IBAction), or do anything which needs the controller, the app crashes. What am I doing wrong?
Thanks!
Create a strong reference for an iVar or property for tabBarVC and change this line:
TabBarViewController *tabBarVC = [[TabBarViewController alloc] init];
To:
tabBarVC = [[TabBarViewController alloc] init];
Or
self.tabBarVC = [[TabBarViewController alloc] init];
Yes you can..! have the controllers you want to display as iVars of the view controller you want to display in. Then just use,
[MainController addSubview:desiredConroller1.view];
[MainController addSubview:desiredConroller2.view];
You can load the controller from the storyboard using,
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"storyboard_name" bundle:nil];
desiredController1 = [membershipStoryboard instantiateInitialViewController];
you can also use instantiateViewControllerWithIdentifier:

UIViewController frame changes every time I ran the app

I have the following code:
PNRProfileViewController *vc = [[PNRProfileViewController alloc] initWithNibName:#"PNRProfileViewController" bundle:nil];
vc.delegate = self;
self.profileVC_ = vc;
UINavigationController *controller = [[UINavigationController alloc] initWithRootViewController:self.profileVC_];
AHLog(#"FRAME IS %#", NSStringFromCGRect(self.profileVC_.view.frame));
controller.view.frame = self.profileVC_.view.frame;
controller.view.autoresizingMask = self.profileVC_.view.autoresizingMask;
self.currentViewController_ = controller;
when I run this code, the frame height I got changes every time.. it's alternating between 416 and 460. I have no idea why this is. Any clue?
44 pixels is the height of the navigation bar.
To keep the navigation bar and have your nib respect its size, go into your .xib file, select the view, then on the attributes tab, set the tab bar drop down to navigation bar.
To remove the navigation bar, after you alloc your NavigationController call controller.navigationBarHidden = YES;

Display clearColor UIViewController over UIViewController

I have a UIViewController view as a subview/modal on top of another UIViewController view, such as that the subview/modal should be transparent and whatever components is added to the subview should be visible. The problem is that I have is the subview shows black background instead to have clearColor. I'm trying to make UIView as a clearColor not black background. Does anybody know what is wrong with it? Any suggestion appreciated.
FirstViewController.m
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
[vc setModalPresentationStyle:UIModalPresentationFullScreen];
[self presentModalViewController:vc animated:NO];
SecondViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.opaque = YES;
self.view.backgroundColor = [UIColor clearColor];
}
RESOLVED: I fixed the issues. It is working so well for both of iPhone and iPad. Modal View Controller with no black background just clearColor/transparent. The only thing that I need to change is I replaced UIModalPresentationFullScreen to UIModalPresentationCurrentContext. How simple is that!
FirstViewController.m
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
vc.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:vc animated:NO completion:nil];
NOTICE: If you are using a modalPresentationStyle property of navigationController:
FirstViewController.m
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
vc.view.backgroundColor = [UIColor clearColor];
self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:vc animated:NO completion:nil];
NOTICE: The bad news is that the above solution doesn't work on iOS 7. The good news is that I fixed the issue for iOS7! I asked somebody for help and here is what he said:
When presenting a view controller modally, iOS removes the view controllers underneath it from the view hierarchy for the duration it is presented. While the view of your modally presented view controller is transparent, there is nothing underneath it except the app window, which is black. iOS 7 introduced a new modal presentation style, UIModalPresentationCustom, that causes iOS not to remove the views underneath the presented view controller. However, in order to use this modal presentation style, you must provide your own transition delegate to handle the presentation and dismiss animations. This is outlined in the 'Custom Transitions Using View Controllers' talk from WWDC 2013 https://developer.apple.com/wwdc/videos/?id=218 which also covers how to implement your own transition delegate.
You may see my solution for the above issue in iOS7: https://github.com/hightech/iOS-7-Custom-ModalViewController-Transitions
iOS8+
In iOS8+ you can now use the new modalPresentationStyle UIModalPresentationOverCurrentContext to present a view controller with a transparent background:
MyModalViewController *modalViewController = [[MyModalViewController alloc] init];
modalViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self presentViewController:modalViewController animated:YES completion:nil];
RESOLVED: I fixed the issues. It is working so well for both of iPhone and iPad. Modal View Controller with no black background just clearColor/transparent. The only thing that I need to change is I replaced UIModalPresentationFullScreen to UIModalPresentationCurrentContext. How simple is that!
FirstViewController.m
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
vc.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:vc animated:NO completion:nil];
NOTICE: If you are using a modalPresentationStyle property of navigationController:
FirstViewController.m
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
vc.view.backgroundColor = [UIColor clearColor];
self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:vc animated:NO completion:nil];
NOTICE: The bad news is that the above solution doesn't work on iOS 7. The good news is that I fixed the issue for iOS7! I asked somebody for help and here is what he said:
When presenting a view controller modally, iOS removes the view controllers underneath it from the view hierarchy for the duration it is presented. While the view of your modally presented view controller is transparent, there is nothing underneath it except the app window, which is black. iOS 7 introduced a new modal presentation style, UIModalPresentationCustom, that causes iOS not to remove the views underneath the presented view controller. However, in order to use this modal presentation style, you must provide your own transition delegate to handle the presentation and dismiss animations. This is outlined in the 'Custom Transitions Using View Controllers' talk from WWDC 2013 https://developer.apple.com/wwdc/videos/?id=218 which also covers how to implement your own transition delegate.
You may see my solution for the above issue in iOS7: https://github.com/hightech/iOS-7-Custom-ModalViewController-Transitions
So for purely visual thinkers and storyboard fans, you can do:
1. Presenting View Controller
2. Presented View Controller
Swift 3 & iOS10 solution :
//create view controller
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "RoadTripPreviewViewController")
//remove black screen in background
vc.modalPresentationStyle = .overCurrentContext
//add clear color background
vc.view.backgroundColor = UIColor.clear
//present modal
self.present(vc, animated: true, completion: nil)
This is from xCode 7 beta 4 using a control drag segue. Simply set the background of your destination to clear, and set the segue properties in IB as this (nb. Presentation can also be "Over Full Screen"):
I found the easiest way to get it to work on iOS7 and iOS8 is to add set the presentationStyle to UIModalPresentationOverCurrentContext on the modallyPresentedVC (ViewController which you want to present modally) because of iOS8:
[modallyPresentedVC setModalPresentationStyle:UIModalPresentationOverCurrentContext];
[modallyPresentedVC.navigationController setModalPresentationStyle:UIModalPresentationOverCurrentContext];
and UIModalPresentationCurrentContext on presentingVC (the controller which presents the modallyPresented) because of iOS7:
[presentingVC setModalPresentationStyle:UIModalPresentationCurrentContext];
[presentingVC.navigationController setModalPresentationStyle:UIModalPresentationCurrentContext];
Because things are handled differently on iOS7 and iOS8. Of course you don't have to set the navigationController properties if you are not using one. Hope that helps.
Swift2 version :
let vc = self.storyboard!.instantiateViewControllerWithIdentifier("YourViewController") as! YourViewController
vc.view.backgroundColor = UIColor.clearColor()
vc.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen // orOverCurrentContext to place under navigation
self.presentViewController(vc, animated: true, completion: nil)
Another way (no need to create custom transition and works on iOS 7)
Using Storyboard:
Create the Child View Controller with freedom size, set view width to 500x500 (for example) and add the next method:
- (void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
self.view.superview.bounds = CGRectMake(0, 0, 500, 500);
self.view.superview.backgroundColor = [UIColor clearColor];
}
Then create a Modal segue with Form Sheet and test it.
iOS 7 solution with custom segue:
CustomSegue.h
#import <UIKit/UIKit.h>
#interface CustomSegue : UIStoryboardSegue <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning>
#end
CustomSegue.m
#import "CustomSegue.h"
#implementation CustomSegue
-(void)perform {
UIViewController* destViewController = (UIViewController*)[self destinationViewController];
destViewController.view.backgroundColor = [UIColor clearColor];
[destViewController setTransitioningDelegate:self];
destViewController.modalPresentationStyle = UIModalPresentationCustom;
[[self sourceViewController] presentViewController:[self destinationViewController] animated:YES completion:nil];
}
//===================================================================
// - UIViewControllerAnimatedTransitioning
//===================================================================
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
return 0.25f;
}
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
UIView *inView = [transitionContext containerView];
UIViewController* toVC = (UIViewController*)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromVC = (UIViewController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
[inView addSubview:toVC.view];
CGRect screenRect = [[UIScreen mainScreen] bounds];
[toVC.view setFrame:CGRectMake(0, screenRect.size.height, fromVC.view.frame.size.width, fromVC.view.frame.size.height)];
[UIView animateWithDuration:0.25f
animations:^{
[toVC.view setFrame:CGRectMake(0, 0, fromVC.view.frame.size.width, fromVC.view.frame.size.height)];
}
completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
//===================================================================
// - UIViewControllerTransitioningDelegate
//===================================================================
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
return self;
}
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
//I will fix it later.
// AnimatedTransitioning *controller = [[AnimatedTransitioning alloc]init];
// controller.isPresenting = NO;
// return controller;
return nil;
}
- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator {
return nil;
}
- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator {
return nil;
}
#end
Solution based on hightech code.
For Me this Works:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"MMPushNotificationViewController"];
vc.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
#ifdef __IPHONE_8_0
if(IS_OS_8_OR_LATER)
{
self.providesPresentationContextTransitionStyle = YES;
self.definesPresentationContext = YES;
[vc setModalPresentationStyle:UIModalPresentationOverCurrentContext];
}
#endif
[self presentViewController:vc animated:NO completion:nil];
MMPushNotificationViewController is the Transparent View controller and also I have made the MMPushNotificationViewController's view color as clearcolor. Now All that I have Done and made my Transparentviewcontroller.
For iOS7
There is now a way to achieve this using the iOS7 custom transitions, this way :
MyController * controller = [MyController new];
[controller setTransitioningDelegate:self.transitionController];
controller.modalPresentationStyle = UIModalPresentationCustom;
[self controller animated:YES completion:nil];
To create your custom transition, you need 2 things :
A TransitionDelegate object (implementing
<UIViewControllerTransitionDelegate>)
An "AnimatedTransitioning" object
(implementing <UIViewControllerAnimatedTransitioning>)
You can find more informations on custom transitions in this tutorial.
Works Great on iOS7 and iOS8
UIViewController* vc=[[UIViewController alloc]initWithNibName:#"VC" bundle:nil];
vc.view.alpha=0.7;
[vc setModalPresentationStyle:UIModalPresentationOverCurrentContext];
self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:vc animated:NO completion:nil];
You also can 're-add' the window to the view.
OneViewController *vc = [[OneViewController alloc] init];
if ([self respondsToSelector:#selector(presentViewController:animated:completion:)]) {
[self presentViewController:vc animated:YES completion:nil];
} else {
[self presentModalViewController:vc animated:YES];
}
[[[UIApplication sharedApplication] keyWindow] insertSubview:self.view atIndex:0];
And in this way, presenting can be animated.
For iOS 7 and only by using Interface Builder it can be accomplished by setting the Presentation to "Over Current Context" on all the view controllers involved in the modal presentation. Even for navigation controllers.
For instance, set it on all these view controllers:
NavController -> RootViewController -> ModalViewController
I haven't played around with Storyboard/Interface builder much, but what pops out at me is that you're telling the view to be clear colored (ie. 100% alpha/see-through) and also telling it to be opaque (0% alpha--completely solid). These two things don't seem to mesh. I'd comment out the self.view.opaque = YES; line and see if it works then ;)
Ah, something else I just thought of--its entirely possible that your view controller DOES have the alpha background, but of course the alpha will be showing through to the color of the base window or root view controller of the program, which is by default black. The very base layer of your entire app can't have a transparent background--transparent to what? What's behind it? There has to be something to see THROUGH the transparency. Does that make sense?
Just use "self.modalPresentationStyle = UIModalPresentationCurrentContext;", in presenting view
Will work fine :)

UIPopoverController inRect issue

I have a UIViewController that contains a UIView subclass as a subview. In the subview, I dynamically create another UIView. When the innermost view is created then the UIViewController is informed via a delegation that it must show a UIPopovercontroller whose arrow head need to be pointing to the inner most view. In the delegate method call, I also pass the origin of the inner most view so that the UIViewcontroller make use of this CGPoint to create the popover controller. The problem is that the UIPopovercontroller is not being positioned at the desired location.
MyController* myController = [ [ MyController alloc] init];
UINavigationController *aNavController = [[UINavigationController alloc] initWithRootViewController: myController];
self.popOver = [[[UIPopoverController alloc]
initWithContentViewController:aNavController] autorelease];
[aNavController release];
CGRect rect;
//CGPoint p = CGPointMake(currentPage.frame.size.width/2, currentPage.frame.size.height/2);
rect.origin = point; //here point is the origin of the inner most view
rect.size = self.view.frame.size;
[self.popOver presentPopoverFromRect: rect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
What I am missing in this code that is forcing the popover to appear deviated from the position instead of at the desired place.
Thanks
I think your are not passing the correct view to your popOver, check once ...
[self.popOver presentPopoverFromRect: rect inView:myInnerView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
The rect you are presenting your popover from may be too large.
You have it set to the size of the entire view instead of the size of your inner most view.