Refresh ViewController on TabBarController - iphone

I have a tabBarController with three viewControllers on it.
When viewController 1 is selected and I make a 90 degrees I hide the tabBar and I have to addsubview the current view to the tabBarController, otherwise a blank space appears where the tabBar was.
If now I rotate the iPhone to the previously orientation (the vertical normal position) I removeFromSuperview the view, but no view is shown on the view controller, I suppose the original view (the one before the addsubview call) should be shown, in fact if I select the second viewController and later I go back to the viewController 1 the view appears perfectly.
I don´t understand why this happens, could you help me?
Update:
I think the problem is that I add a view over the tabbarcontroller (self.view addSubview:vista_AS.view]) I need this to make the tabbar not visible, and later, when I remove this view the tabbarcontroller loses in some way the viewcontroller 0 view reference. What I don´t understand is why when I change to viewcontroller 1 and then back to 0 the view is OK. Is there some way to reload viewcontroller 0 view??
Update 2:
Included author's code from a suggested edit to the answer
This is my code:
if(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
self.tabBar.hidden = TRUE;
vista_AS = [delegate.tabBarController.viewControllers objectAtIndex:0];
vista_AS.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:vista_AS.view];
}
else {
if ( (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight) )
{
[vista_AS.view removeFromSuperview];
self.tabBar.hidden = FALSE;
}

It appears your view controller 1 is being deallocated, either by yourself due to over releasing or by the system due to memory. Post some code showing how you attach and remove the view covering the tab bar. This may hold the answer.

When you add vista_AS as a subview of the tabBarController you change the parent view of vista_AS to its newest view parent, therefore breaking the link with tabBarController.
When you change iPhone's orientation, you remove vista_AS from its superview, but the link between the tabBarController and your view it is still broken. I believe that's why you can't see the view. A solution would probably go either by re-assigning vista_AS's parent to tabBarController.view or to do [tabBarController.view addSubview:vista_AS].

Related

Auto-Resizing a dynamic view when rotated

I have a tab bar application where everything is working fine. I have rotations of the device all working fine with the various Tab Bar View controllers.
Alas it was suggested that a couple of the View Controllers needed a help page. To this end I created a new ViewController that contains a UIWebView (where help can be built into an HTML file).
I create the new "HelpViewController" as follows:
mpHelpPage = [[HelpPageViewController alloc] init];
[mTabBarController.view addSubview: mpHelpPage.view];
[mpHelpPage retain];
mpHelpPage.view.alpha = 0.75f;
This brings up the help page no problems when I'm in portait mode. Unfortunately when I'm in landscape mode and I do the above code it adds the HelpViewController in Portrait (meaning it extends off the bottom of the screen).
As such when I alloc the ViewController above I need some way of telling the ViewController to rotate to the current device orientation.
I am, however, at a loss as to how to get it to do this. Any help would be much appreciated!
I handle this annoyance by putting an orientation check in viewWillAppear:, e.g.
if (self.interfaceOrientation == UIInterfaceOrientationPortrait ||
self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
// custom code or call willRotate
} else {
// custom code or call willRotate
}
You can also do this if you prefer
if (UIDeviceOrientationIsPortrait(self.interfaceOrientation)) {
// custom code or call willRotate
} else {
// custom code or call willRotate
}
you should either set the frame-property of your subview in willRotateToInterfaceOrientation:duration: of your ViewController
or you write your own View and set the frame-property in layoutSubviews of your View
The added Subview should handle the layout of its subviews.
Since you've added HelpViewController as a subview and no UIViewController controls it, it will not be resized. You can resize HelpViewController's view manually by detecting a change in the orientation in the shouldAutorotateToInterfaceOrientation: method of the current UIViewController. This method passes the current orientation as its argument, so just check which is the current orientation and set a frame accordingly as:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if((interfaceOrientation==UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation==UIInterfaceOrientationLandscapeRight))
mpHelpPage.view.frame = CGRectMake(0,0,480,300);
else
mpHelpPage.view.frame = CGRectMake(0,0,320,460);
return YES;
}
Or, Instead of adding HelpViewControlleras a subView, try [self.navigationController pushViewController:HelpViewController animated:YES];

How can I have a UISegmentedControl swap views in and out, AND still have the ability to rotate orientation?

I have looked around at a number of posts on this topic, but have been unable to fix the issues I am having. I am presenting a modal view that is a UIViewController. I've setup that view to have a UISegmentedControl on the top right that will ideally allow me to switch the view (inside of this modal view).
In order to not cover up my toolbar at the top, I have made a simple UIView in IB, and laid out the dimensions so they don't overlap the toolbar. Now my thinking is that if I add the view I want to add to the UIView when the UISegmentedControl is selected, life will be great:
-(IBAction) indexDidChangeForSegmentedControl:(UISegmentedControl*)seg{
int selectedNum = seg.selectedSegmentIndex;
if([[self.view1 subviews] objectAtIndex:0] != nil){
[[[self.view1 subviews] objectAtIndex:0] removeFromSuperview];
}
if(selectedNum == 0){
[self.view1 addSubview:[(DialogInfo*)[viewsArray objectAtIndex:seg.selectedSegmentIndex] view]];
}else if(selectedNum == 1){
[self.view1 addSubview:[(DialogMetadata*)[viewsArray objectAtIndex:seg.selectedSegmentIndex] view]];
}else if(selectedNum == 2){
[self.view1 addSubview:[(DialogVersions*)[viewsArray objectAtIndex:seg.selectedSegmentIndex] view]];
}else if(selectedNum == 3){
[self.view1 addSubview:[(DialogAssoc*)[viewsArray objectAtIndex:seg.selectedSegmentIndex] view]];
}
}
And that works! But the problem is that when I rotate the device, the view that I really care about, the inner one, won't spin.
I have tried not doing this outer parent UIView approach, and just tried setting the view controller view with a certain frame, but the orientation is still messed up.
I have also tried doing this with a UINavigationController, and just not animating the transition, but I can't get that to work correctly.
So my question is: What do I do?! All I want is to be able to switch between views with a UISegmentedControl and be able to rotate the device to any orientation I need. I've thought through this so much and tried so many different things that I feel like I don't have a clue what is happening anymore.
Thank you for your help
Well it turns out after poking around some more that my resize mask wasn't set properly in IB. DOH!

iPhone - Alternate Landscape View issue

I'm having the landscape mode issue and I can not find the way out. Basically, I'm having a tab bar application and in the first tab i have navigation controller. In this navigation controller, first view contains table with items and after clicking the item, detail view describing the item is pushed.
I need to implement landscape mode for both list and detail view, but for list view, i need to use different view controller for landscape mode (generally, something like cover flow). Detail view is just changing orientation and no need to use alternate view controller in this case.
I tried to achieve this behaviour by implementing modal view controller for list view controller, according to Alternate Views example by Apple. This works fine when I'm in list view (when I turn device into landscape mode, cover flow view controller is correctly presented). Problem comes when I'm showing detail view. When I change the device orientation, cover flow shows up again. What I expected is that cover flow will be presented only in case that list view is on the screen. It seems like modal view controller is always visible no matter what VC is currently on the stack of NC.
It seems to me that presenting modal VC as landscape view for particular VC is not working for multiple navigation levels.
I also tried to add landscape view as a subview into view controllers view. When using this solution, i have no problem with navigation levels, but issue here is that tab bar is not hidden in landscape mode. I need to hide tab bar for cover flow, which is achieved by presenting modal VC.
I will appreciate any help with this issue.
Great thanks!
In the detail view controller, you could set up a different view entirely using something like this (code from a recent project of mine):
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toOrientation
duration:(NSTimeInterval)duration
{
if ([graphView superview]) {
if (toOrientation == UIInterfaceOrientationPortrait ||
toOrientation == UIInterfaceOrientationPortraitUpsideDown) {
[graphView removeFromSuperview];
}
} else {
if (toOrientation == UIInterfaceOrientationLandscapeLeft ||
toOrientation == UIInterfaceOrientationLandscapeRight) {
[[self view] endEditing:YES];
[[self view] addSubview:graphView];
}
}
}
And now to hide the tabbar when you are in landscape (bit of a hack, but works):
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
UIInterfaceOrientation toOrientation = self.interfaceOrientation;
if ( self.tabBarController.view.subviews.count >= 2 )
{
UIView *transView = [self.tabBarController.view.subviews objectAtIndex:0];
UIView *tabBar = [self.tabBarController.view.subviews objectAtIndex:1];
if(toOrientation == UIInterfaceOrientationLandscapeLeft ||
toOrientation == UIInterfaceOrientationLandscapeRight) {
transView.frame = CGRectMake(0, 0, 480, 320 );
tabBar.hidden = TRUE;
}
else
{
transView.frame = CGRectMake(0, 0, 320, 480);
tabBar.hidden = FALSE;
}
}
}
For this project, I added a view called "graphView" that I wanted to appear if and only if in landscape mode, and then I wanted to tabbar to be hidden. This sounds similar to what you're after, I think.
The only potential problem I foresee is that if you enter landscape mode before the detail view is pushed, things could get wonky. Therefore you may want to use these methods in the list view controller instead. This particular problem never arose for me, but it's something I thought about before I realized it was moot.

issue with positioning of pop over view

When I am switching between Portrait to Landscape view (&Vice Versa) in iPad, position of my popover view gets garbled. Here is how I am calculating frame of my popover view:
aRect = self.myElement.frame;
aRect.origin.x += aRect.size.width;
[aPopOver presentPopoverFromRect:aRect inView:self.myElement.superview permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];
Please tell me whats wrong here?
From the UIPopoverController documentation: (emphasis mine)
If the user rotates the device while a
popover is visible, the popover
controller hides the popover and then
shows it again at the end of the
rotation. The popover controller
attempts to position the popover
appropriately for you but you may have
to present it again or hide it
altogether in some cases. For example,
when displayed from a bar button item,
the popover controller automatically
adjusts the position (and potentially
the size) of the popover to account
for changes to the position of the bar
button item. However, if you remove
the bar button item during the
rotation, or if you presented the
popover from a target rectangle in a
view, the popover controller does not
attempt to reposition the popover. In
those cases, you must manually hide
the popover or present it again from
an appropriate new position. You can
do this in the
didRotateFromInterfaceOrientation:
method of the view controller that you
used to present the popover.
ok, i notice something weird about your code.
any reason you are adding the size of the wide to the origin of aRect's x position?
aRect.origin.x += aRect.size.width;
im assuming you want this to be the top right corner....
You can uncomment the code in your .m file and make it like so:
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
Return YES; // for supported orientations
//otherwise return (interfaceOrientation == UIInterfaceOrientationLandscape); if you want only landscape mode.
}
Or what i would do in your situation if you want to layout your subviews is use the didRotateFromIntferfaceOrientation: like so:
(void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
[self layoutSubviews];
}
and also layoutSubviews
- (void)layoutSubviews
{
NSLog(#"layoutSubviews called");
...recalc rects etc based on the new self.view.bounds...
}
It works like so.
PK
This is an old question, but I see it wasn't clear to OP what he should do with Kris Markel's suggestion. This is documented in Technical Q&A QA1694. Just present the popover again.
Let's say you've put your popover code above in a method called showPopover. Just call that method on rotation, first making sure it's visible:
-(void)showPopover {
aRect = self.myElement.frame;
aRect.origin.x += aRect.size.width;
[self.aPopOver presentPopoverFromRect:aRect inView:self.myElement.superview permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];
}
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)oldOrientation
{
if ([self.aPopover isPopoverVisible]) {
[self showPopover];
}
}
Use the below mentioned UIPopoverPresentationControllerDelegate method in the viewcontroller.
func popoverPresentationController(_ popoverPresentationController: UIPopoverPresentationController,
willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>,
in view: AutoreleasingUnsafeMutablePointer<UIView>) {
rect.pointee = self.view.bounds
}

iPhone screen rotates at random ?

I use a tabBar Controller as root controller. It has 4 tabs and each of its ViewControllers has
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return YES;
}
as well as the tabBarController itself.
But when I rotate the device (real or simulator), the screen turns at random! If it doesn't turn when I open the application it would have the same behavior until I quit the app.
I tried to add the 4 viewControllers one by one in IB to see if one was problematic, but I obtained the same issue. It only always turns when there is no tabs at all!
Please tell me if you have any ideas. Thanks!
You set every view controller to say that it responds to any possible orientation. Therefore, every view will attempt to rotate to every orientation.
Views don't really automatically rotate. You usually have to manage the placement of subview programmatically in all but the simplest views.
If you have no custom orientation code, you're probably seeing the views try to draw the portrait view in the landscape frame or vice versa. If you have autoresize subviews set your subviews will appear to scatter across the screen in a seemingly random pattern. The more you change orientation, the more random the placement becomes.
For complex views, I like to create separate viewController/view pairs for each orientation. Then I put the views in a nav controller. As the orientation changes, each view controller will push or pop the appropriate view controller for the coming orientation onto/off the stack. To the user, this looks like a single view is gracefully redrawing itself. (This is especially useful if you have non-standard UI elements that have to be manually rotated with transforms)
You have to subclass UITabBarController and implement shouldAutorotateToInterfaceOrientation:
Actually, I just want my first tab view controller to rotate. So I put this code in my custom tabBarController :
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
if (self.selectedIndex == 0) {
return toInterfaceOrientation != UIInterfaceOrientationPortraitUpsideDown;
}else {
return toInterfaceOrientation == UIInterfaceOrientationPortrait;
}
}
but I had the same problem. I use a custom orientation code for my first tab view controller when turning to landscape. Called with the following function in my custom tabBarcontroller:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (toInterfaceOrientation == UIInterfaceOrientationPortrait) {
//rotation to Portrait
lastOrientation = toInterfaceOrientation;
[[UIApplication sharedApplication] setStatusBarHidden:NO animated:NO];
[self.selectedViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
else if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
if (!UIInterfaceOrientationIsLandscape(lastOrientation)) {
//rotation to Landscape
[self.selectedViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
lastOrientation = toInterfaceOrientation;
}
}
I found that if you set the selected tab programmatically the tabViewController rotates erratically.