Adding Subviews on the top of MainViewController - ios

I am working to get user survey before user starts using my app, it is a typically collection of data for my research.
My problem is to add subview on the top of mainviewcontroller.
I have two subviewcontroller as you can see in the first screenshoots. I would like to add first subview on the mainviewcontroller, and whenever user clicks on next customized button, then firstsubview disappear and secondsubview appear on the top of mainviewcontroller.
firstsubview implemented as follows:
CGRect rect = [firstSurveyViewController.view frame];
rect.origin.x = 5;
rect.origin.y = 5;
[firstSurveyViewController.view setFrame:rect];
[self.view addSubview:firstSurveyViewController.view];
But I want to drop the firstsubview and add the second when user clicks on next button.
How could I implement?

For composing modal view controllers, you have two real options (ignoring cool stuff under NDA):
Use the Container View Controller pattern to insert the inner view controller into its parent.
Add a new window with that view controller, similar to how you would do it in your AppDelegate. Create the window, add your child as a root view controller, make it key and visible. This is actually what UIAlertView does to perform a similar behavior to your app.
I can't say what would be better for your case, but I have more experience with container view controllers so I'll give you the highlights. To add a child view you will need these steps (from the link above) in your parent view controller:
- (void) displayContentController: (UIViewController*) content;
{
[self addChildViewController:content]; // 1
content.view.frame = [self frameForContentController]; // 2
[self.view addSubview:self.currentClientView]; // 3
[content didMoveToParentViewController:self]; // 4
}
This will:
Add your child view controller.
Set the frame to whatever you want. This could be self.view.bounds if you want it to take up the full space.
Add the view to its parent.
Notify the child view controller that it was added.
To remove a child view controller you would do the opposite, again from the link:
- (void) hideContentController: (UIViewController*) content
{
[content willMoveToParentViewController:nil]; // 1
[content.view removeFromSuperview]; // 2
[content removeFromParentViewController]; // 3
}
This will:
Notify your child view controller that it will disappear.
Remove its view from the visual stack.
Remove it from its parent.

You have got two options.
Use both controllers as modal controllers. After tapping Next on first controller, dismiss it and call second controller modally.
Another much better option (in my opinion) is to present these two series of controllers one after another using modal UINavigationController. You can push your controllers in navigation controller, and when done, you can dismiss it and show your main controller.
EDIT
See this post.

Transitioning between views is easy-
1) Straight forward
-(IBAction):onNextButtonClick:(id)sender
{
[self.firstViewController.view removeFromSuperView];
self.secondViewController.view.frame = newFrame;
[self.view addSubView:self.secondViewController.view];
}
2) If you want some fancy animations try this-
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionTransitionCurlDown animations:^{
[self.firstViewController.view removeFromSuperView];
self.secondViewController.view.frame = newFrame;
[self.view addSubView:self.secondViewController.view];
} completion:^(BOOL finished) {
//Completion
}];

Related

How to fix the Table view as Dialog or Popup For all View Controllers in ios

Totally i have 5 view controllers and i have fixed one button as Account Button in all 5 view controllers, once i clicked the Account button it need to show the tablewView like below image,first i tried the one table view to show hide in first view controller i want to show the table view for all five view controller when i clicked the account button,
This i want to show in all view controllers,
When i click any option it navigate to
My Account -> AccountVC,
Track Order -> TrackOrderVC,
Customer Services ->CusServicesVC
same thing i implemented in one of my project.create subclass of uiview and in .h file write this two method
- (void)showMenuViewAnimatedWithFrame:(CGRect)rect;
- (void)hideMenuViewAnimated;
and in .m file create a object of table view implement it's delegate and datasource method and write this code as
- (void)showMenuViewAnimatedWithFrame:(CGRect)rect{
listTableView.frame = CGRectMake(0, 10, rect.size.width, rect.size.height - 10);
[UIView animateWithDuration:0.3f animations:^{
self.frame = rect;
}];
}
- (void)hideMenuViewAnimated{
[UIView animateWithDuration:0.3f animations:^{
self.frame = preViewframe;//set your view frame to preViewframe
}];
}
finally call this methods in your view controller where you want to show a dropdown picker by creating its views object.if you set correctly i will look like:

How to do a view controller transition where the selected view stays in place and fades out

I am interested in doing a transition where it is a standard push transition but that the fromViewController will persist the selected UIView over the top of the toViewController while the toViewController slides into place. I have tried to mock this up below.
The boxes on the left hand side represent UIViews and the third one (the brown one_ is the one that is clicked. In the middle figure, the fromViewController slides to the left (eve as the toViewController slides in. The selected UIView stays in place and has an animation that fades it out.
I am not so familiar with Custom Transitions but am thinking this is how it woulf be done. Possibly in the context of a Container View Controller but, honestly, not that sure. Any ideas on how to achieve this effect? I'm hoping it's also possible to run the effect in reverse when the user hits the 'Back' button.
It is very easy to implement. First of all, create a custom Container Controller. Do you need Navigation-controller-like controllers stack? If yes, implementation will be quite more complicated. Anyway, it will look something like this:
- (void)showViewController:(UIViewController *)viewController
selectedView:(UIView *)selectedView
{
// Tell prev. controller about pending removing
[_currentController willMoveToParentViewController:nil];
// Add the next controller
[self addChildViewController:viewController];
// Move selected view to the Containers view
[self.view addSubview:selectedView];
// Add toView below fromView
[self.view insertSubview:viewController.view
belowSubview:_currentController.view];
// Animate whatever you need
[UIView animateWithDuration:0.25
animations:^
{
// Move from view
CGPoint fromViewCenter = viewController.view.center;
fromViewCenter.x = -0.5 * viewController.view.frame.size.width;
viewController.view.center = fromViewCenter;
// Fade out the selected view
selectedView.alpha = 0;
}
completion:^
{
// Clean
[_currentController.view removeFromSuperview];
// Finally remove prev. controller from the hierarchy
[_currentController removeFromParentViewController];
// Notify
[viewController didMoveToParentViewController:self];
}];
}
Hope you will manage to make reverse by yourself.

uitableview with header like instagram user profile

I've been struggling with this for quite a while now.
I have to implement an user profile similar to what Instagram has in their ios app.
When clicking on the first to buttons on that tab bar like thing all the contents downwards from it changes. The tableview that is displayed on the bottom part has dynamic size so they keep account of that also.
I have something implemented where the top part is a UIView with 5 buttons and based on them the bottom part (witch is like a container view) changes content. And these two (top uiview and bottom container view) are part of UIScrollView. But this way I can't get information back in time on the size about the tableview's size that I want to display in the bottom part in order to modify the UIScrollView's size. And I have a feeling this is a flawed way to do it.
I would really appreciate any ideas oh how to implement this king of interaction. Thank you.
I believe it's a headerView on a UITableView or a UICollectionView, depending on which view mode you have selected. When you tap one of the buttons it changes out the UITableView to a UICollectionView or vice versa.
You want to keep track of the current contentOffset for whichever is being displayed (UICollectionView and UITableView are both subclasses of UIScrollView so you will be able to get this from both) and then set the contentOffset on the view you're switching to.
Setup an ivar for the UIView header subclass so you can easily re-use it.
This is what I have. My problem is that I'm mot getting back in useful time the tableview's frame height from the tableview controller to the UserProfileViewController in order to change the latter's scrollview size. I also feel that I'm somehow doing this backwards so any suggestions are more than welcome.
This view has two parts: an upper part and a lower part. The parent view is a scroll view. What I wanted to achieve with this is having a sort of tab bar in the upper part that will controll waht will appear in the lower part.
The upper part has a flip animation when the upper left button is pressed to reveal another view.
The way this is achieved is by having 2 views: a dummy view and the back view. The dummy view has the front view as a child. The front view is the one that containes all the buttons.
The code for this animation is achieved in this way:
- (IBAction)infoButtonPressed:(id)sender
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.hoverView cache:YES];
if ([self.headerView superview]) {
[self.headerView removeFromSuperview];
[self.hoverView addSubview:self.backOfHeaderView];
[self.infoButton removeFromSuperview];
[self.backOfHeaderView addSubview:self.infoButton];
} else {
[self.backOfHeaderView removeFromSuperview];
[self.hoverView addSubview:self.headerView];
[self.infoButton removeFromSuperview];
[self.headerView addSubview:self.infoButton];
}
[UIView commitAnimations];
}
The lower part is made out of a container view that acts as a place holder.
When a button is pressed a different view controller is displayed in the container view.
Each view controller has a container view of it's own. The specific view of that view controller (tableview) is added to it's container view when the controller is loaded. It also makes sure that if the tableview is already added to the container view it will be removed. All this is done in each specific view controller.
In the view controller of the User Profile view there is an instance of the container view and one of a UIViewController that also acts as a placeholder(named currentViewController from now on). When a specific button is pressed it checks if the an instance of the view controller that we want to display already exists. If not it will make one and will set it's tableview's frame to the bounds of the container view. After that it will remove the currentViewController's view from the superview and the currentViewController itself from the parent viewcontroller to make sure that if there is something assigned to these they will not be there. Then it goes and assigns the desired viewcontroller to the currentViewController. It also assigns the desired viewcontroller's containerView instance to the containerview in the parent viewcontroller (the User Profile viewcontroller). At the end it will add the desired viewcontroller as a child to the main viewcontroller (the User Profile viewcontroller) and desired viewcontroller's view to the containerView of the main viewcontroller.
This is the code for one of the buttons:
//Check if there is an instance of the viewcontroller we want to display. If not make one and set it's tableview frame to the container's view bounds
if(!_userWallViewController) {
self.userWallViewController = [[WallViewController alloc] init];
// self.userWallViewController.activityFeedTableView.frame = self.containerView.bounds;
}
[self.userWallViewController.containerView addSubview:self.userWallViewController.activityFeedTableView];
//If the currentviewcontroller adn it's view are already added to the hierarchy remove them
[self.currentViewController.view removeFromSuperview];
[self.currentViewController removeFromParentViewController];
//Add the desired viewcontroller to the currentviewcontroller
self.currentViewController = self.userWallViewController;
//Pass the data needed for the desired viewcontroller to it's instances
self.userWallViewController.searchURLString = [NSString stringWithFormat:#"event/user/%#/", self.userID];
self.userWallViewController.sendCommentURLString = [NSString stringWithFormat:#"event/message/%#", self.userID];
self.userWallViewController.totalCellHeight = ^(float totalCellHeight){
self.userWallViewController.numberOfCells = ^(float numberOfCells){
NSLog(#"The total number of cells: %f", numberOfCells);
NSLog(#"The total cell height: %f", totalCellHeight);
self.scrollView.contentSize = CGSizeMake(320.0, totalCellHeight + 172.0 + 33.0);
CGRect newFrame = self.userWallViewController.containerView.frame;
newFrame.size.height = totalCellHeight + 33.0;
self.userWallViewController.containerView.frame = newFrame;
NSLog(#"Container view: %f", self.containerView.frame.size.height);
NSLog(#"Scroll view: %f",self.scrollView.contentSize.height );
};
};
//Add this containerview to the desired viewcontroller's containerView
self.userWallViewController.containerView = self.containerView;
//Add the needed viewcontroller and view to the parent viewcontroller and the containerview
[self addChildViewController:self.userWallViewController];
[self.containerView addSubview:self.userWallViewController.view];
[self performSelector:#selector(changeScrollView) withObject:self afterDelay:0.5];
//CLEAN UP THE CONTAINER VIEW BY REMOVING THE PREVIOUS ADDED TABLE VIEWS
[self.userFansViewController.userSimpleTableView removeFromSuperview];
[self.fanOfViewController.userSimpleTableView removeFromSuperview];
[self.userPublishedMovellaListViewController.gridView removeFromSuperview];
[self.userPublishedMovellaListViewController removeFromParentViewController];
self.userPublishedMovellaListViewController = nil;
}
I know this answer is over a year late, but I wanted to state my hypothesis on it...just incase it might help someone else later. Im implementing a similar view and came to this conclusion. Anyone is welcomed to correct me if I'm wrong.
I think that perhaps the top view is a header view and the two options that seem like a collection view and a table view are both collection views.
Because the layout of collection views can be fine tuned to the most minute details, I think the view that looks like a table view is just a really specifically designed collection view. And when switching between the views, the collection view's data and properties are being swapped and reloaded.

Is it correct to move the navigation bar frame?

I have a navigation bar based ipad app.
At some point I want to push another view controller into the views controller hierarchy. Then, when the users tabs some button I want to show a leftMenu controller. To do so I have two views:
A content view which has all the content
And a not visible view which is the leftMenu. This one is under the content view.
So when the user presses the button, what Im doing right now is moving the content view and the navigation bar to the right to make the leftMenu visible:
self.navigationController.navigationBar.frame = CGRectMake(271.0, self.navigationController.navigationBar.frame.origin.y, self.navigationController.navigationBar.frame.size.width, self.self.navigationController.navigationBar.frame.size.height);
self.contentView.frame = CGRectMake(271.0, self.contentView.frame.origin.y, self.contentView.frame.size.width, self.contentView.frame.size.height);
This is working, but the first row in the left menu is not "clickable" where the nav bar is supossed to be. Its like the navigation bar is still there capturing the tab events.
Is it correct to do?:
self.navigationController.navigationBar.frame = CGRectMake(271.0, self.navigationController.navigationBar.frame.origin.y, self.navigationController.navigationBar.frame.size.width, self.self.navigationController.navigationBar.frame.size.height);
If not, whats the propper way to achieve what I want?
Heres and image ilustrating what the problem is:
I think it's best to use a custom container controller to do this kind of thing, rather than moving a navigation bar. In IB, this can be set up quite easily. Start with a UIViewController, add a container view to it, and size how you want. Then in the inspector, set its x value to minus its width, which will put it off screen to the left. Then add another container view and size it to be full screen. You can then delete the view controller that you got with that container view, and right drag from the container view to your initial navigation controller (of your already setup UI) to connect it up with an embed segue. The UIViewController that you started with should be made the initial view controller of the storyboard. To move in the side view, I use this code in that custom container controller:
-(void)slideInLeft {
if (isRevealed == NO) {
[UIView animateWithDuration:.6 animations:^{
leftView.center = CGPointMake(leftView.center.x + 100, leftView.center.y);
mainView.center = CGPointMake(mainView.center.x + 100, mainView.center.y);
} completion:^(BOOL finished) {
isRevealed = YES; ;
}];
}else{
[UIView animateWithDuration:.6 animations:^{
leftView.center = CGPointMake(leftView.center.x - 100, leftView.center.y);
mainView.center = CGPointMake(mainView.center.x - 100, mainView.center.y);
} completion:^(BOOL finished) {
isRevealed = NO;
}];
}
}
leftView and mainView are IBOutlets to the 2 container views. I call this method from a button in the main view controller (the root view controller of the navigation controller that's embedded in the large container view):
-(IBAction)callSlideIn:(id)sender {
[(ViewController *)self.navigationController.parentViewController slideInLeft];
}
I found a "fast" way to achieve this (and a bit hacky imo)
I added the leftMenu view to the top view in the views hierachy:
UIWindow* window = [UIApplication sharedApplication].keyWindow;
if (!window)
window = [[UIApplication sharedApplication].windows objectAtIndex:0];
[[[window subviews] objectAtIndex:0] addSubview:self.leftMenu.view];
Now it is les deep than the navigation bar and, of course, its clickable

Do I have to use PresentModalViewController?

I'm doing some "interesting" view transitions, and I'm finding myself working around the functionality of "presentModalViewController" in a way that doesn't feel right.
I'd prefer to take total control over the presentation of the modal view controller's view and skip "presentModalViewController" altogether.
However, I'm not sure about the ramifications of doing this.
Currently, I've got code that looks works something like like this (this is just a pseudo-code example, and I can't use the built in transitions, they won't do what I need):
// Create the child view controller:
ModalViewController * child = [[ModalViewController alloc] init];
// Present it:
[parentViewController presentModalViewController:child animated:NO];
// This rect is what the child view's ultimate "destination" should be,
// and, what the parent view's old frame was:
CGRect frame = child.view.frame;
// Put the parent view controller's view back in the window:
[child.view.window insertSubview:parentViewController.view belowSubview:child.view];
// Show it if it's hidden:
[parentViewController.view setHidden:NO];
// Put the parent back where it was:
[parentViewController.view setFrame:frame];
// Put the child at the "top" of the screen (the bottom edge
// of the child's view is at the top of the screen):
[child.view setFrame:CGRectMake(frame.origin.x,
frame.origin.y - frame.size.height,
frame.size.width,
frame.size.height)];
// Animate a transition which slide the parent and child views
// down together:
[UIView animateWithDuration:0.7 animations:^(void) {
child.view.frame = frame;
parentViewController.view.frame = CGRectMake(frame.origin.x,
frame.origin.y + frame.size.height,
frame.size.width,
frame.size.height);
} completion:^(BOOL finished) {
// We're done, remove the parent view from the window
// like it's supposed to be:
[parentViewController.view removeFromSuperview];
}];
[child release];
If you don't want to have UIKit set modalViewController and control the presentation and dismissal of the child view controller, then don't. You can skip the presentModalViewController:animated: call and manually add or remove subviews, or if you want to switch to an entirely new view controller then disconnect the old one's view from the heirarchy and connect the new one, etc. Other ways of presenting include UINavigationController or a UITabBarController, and they don't use the modalViewController methods.
To be more specific, you should set the rootViewController property of your application's UIWindow to the new view controller.
Docs say:
The root view controller provides the content view of the window. Assigning a view controller to this property (either programmatically or using Interface Builder) installs the view controller’s view as the content view of the window. If the window has an existing view hierarchy, the old views are removed before the new ones are installed.
Note that the docs mention an automatic process of installing the view as the content view of the heirarchy. What I'm saying is you can use the provided automatic methods - UIWindow for root views, modalViewController and other systems for non-root views - or you can do it manually, but it's accomplishing the same thing. Particularly since the rootViewController property has only existed since iOS 4, and applications prior to this used auto-generated default code of [window addSubview:rootView] at launch.
If UIKit has some extra magic occurring in [UIWindow setRootViewController:] I'm totally prepared to be corrected on this though.

Resources