How to switch between tabs and directly show pushed view controller? - ios

This is my code:
VideoDetailViewController *VideoDetailVC = [self.storyboard instantiateViewControllerWithIdentifier:#"VideoDetailViewController"];
UINavigationController * navigationController = (UINavigationController *) [[self tabBarController] selectedViewController];
[self.tabBarController setSelectedIndex:0];
[navigationController pushViewController:VideoDetailVC animated:YES];
I am writing this code in tabbar's second index. I want to directly go to the Video Detail screen, which is child view controller of tabbar's zero index. Everything works fine but what I see is: it shows a parent view controller which is tabbar's zero index. After a second it pushes to the Video Detail screen. I just don't want to show the zero index. What is the solution? Help will be appreciated.
EDITED:
#import "TWPhotoCollectionViewCell.h"
#implementation TWPhotoCollectionViewCell
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.imageView = [[UIImageView alloc] initWithFrame:self.bounds];
self.imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.imageView.layer.borderColor = [UIColor blueColor].CGColor;
[self.contentView addSubview:self.imageView];
}
return self;
}
- (void)setSelected:(BOOL)selected {
[super setSelected:selected];
self.imageView.layer.borderWidth = selected ? 2 : 0;
}
#end

Replace below line
[navigationController pushViewController:VideoDetailVC animated:YES];
With
[navigationController pushViewController:VideoDetailVC animated:NO];
It may solve your issue.

Related

UINavigationController title in iOS seems corrupted

When I present a UINavigationController modally and then push (without animation) some UIViewcontrollers onto it, the finally shown navigationItem.title is different from what I would expect.
I tried to narrow my issue down and came up with the following short code to duplicate the issue:
#implementation DummyRootVC
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController:[[Dummy1VC alloc] init]];
[self presentViewController:nc
animated:false
completion:nil];
}
#end
#implementation Dummy1VC
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor=[UIColor whiteColor];
self.navigationItem.title= #"DUMMY1";
[self.navigationController pushViewController:[[Dummy2VC alloc] init]
animated:false];
}
#end
#implementation Dummy2VC
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title= #"DUMMY2";
self.view.backgroundColor=[UIColor yellowColor];
[self.navigationController pushViewController:[[Dummy3VC alloc] init]
animated:false];
}
#end
#implementation Dummy3VC
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor=[UIColor orangeColor];
self.navigationItem.title= #"DUMMY3";
[self.navigationController pushViewController:[[Dummy4VC alloc] init]
animated:false];
}
#end
#implementation Dummy4VC
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title= #"DUMMY4";
self.view.backgroundColor=[UIColor greenColor];
for (UIViewController* vc in self.navigationController.viewControllers) {
NSLog(#"VC Stack: %# Title:%#",vc,vc.navigationItem.title);
}
NSLog(#"End");
}
#end
In AppDelegate I set:
self.window.rootViewController = [[DummyRootVC alloc] init];
When running that code the displayed title is „Dummy 2“ and the back-button is named „Dummy 4“, while I actually would expect a title „Dummy 4“ and a back-button named „Dummy 3“.
The log shows as expected the correct ViewController-Stack and the backgroundColor is (as expected) green (and interestingly is still green after one "back" click):
VC Stack: Title:DUMMY1
VC Stack: Title:DUMMY2
VC Stack: Title:DUMMY3
VC Stack: Title:DUMMY4
End
I could work around that issue since it seems somewhat related to the non-animation setting in combination with presenting the navigation controller modally, but I would like to understand the underlying issue…
Can anyone provide me with some insight? Is this some bug or am I doing (as I suspect) just something the wrong way?
Thanks!
Put the push/present from viewDidLoad to viewWillAppear or viewDidAppear so that the viewController can init it's subview correctly to avoid problem :D

IOS. UITabBarController with navigationController

I had a viewController which contains video view and UITabBarController. UITabBarController contains 3 viewControllers with UINavigationController. The problem is that the frame of first UINavigationController is good (0,20,width,height), but the other two navigationController has wrong frame (0,0,width,height). Status bar is showing, so I don't know what's wrong with them.
Here i create TabBarController :
#interface EEMenuTBC ()
#end
#implementation EEMenuTBC
- (void)viewDidLoad {
[super viewDidLoad];
EEFavoritesVC *favotiteVC = [[EEFavoritesVC alloc] initWithNibAsClassName];
UINavigationController *favotiteNC = [[UINavigationController alloc] initWithRootViewController:favotiteVC];
[favotiteVC.tabBarItem setImage:[UIImage imageNamed:#"favoritesMenuDisabled"]];
[favotiteVC.tabBarItem setTitle:#"Favourites"];
EESearchTVC *searchVC = [[EESearchTVC alloc] initWithNibAsClassName];
UINavigationController *searchNC = [[UINavigationController alloc] initWithRootViewController:searchVC];
[searchVC.tabBarItem setImage:[UIImage imageNamed:#"searchMenuDisabled"]];
[searchVC.tabBarItem setTitle:#"Search"];
EESettingsTVC *settingsVC = [[EESettingsTVC alloc] initWithNibAsClassName];
UINavigationController *settingsNC = [[UINavigationController alloc] initWithRootViewController:settingsVC];
[settingsVC.tabBarItem setImage:[UIImage imageNamed:#"settingsMenuDisabled"]];
[settingsVC.tabBarItem setTitle:#"Settings"];
self.viewControllers = #[favotiteNC, searchNC, settingsNC];
self.tabBar.items[0].selectedImage = [UIImage imageNamed: #"favoritesMenuEnabled"];
self.tabBar.items[1].selectedImage = [UIImage imageNamed: #"searchMenuEnabled"];
self.tabBar.items[2].selectedImage = [UIImage imageNamed: #"settingsMenuEnabled"];
for(UIView *temp in self.tabBar.subviews) {
[temp setExclusiveTouch:YES];
}
}
-(BOOL)prefersStatusBarHidden {
return NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)goToRootVC {
if (_delegateMenuTBC && [_delegateMenuTBC respondsToSelector:#selector(EEMenuTBCDelegateGoToRootVC)]) {
[_delegateMenuTBC EEMenuTBCDelegateGoToRootVC];
}
}
#end
In other ViewController i doing
_menuTBC = [[EEMenuTBC alloc] initWithNibName:#"EEMenuTBC" bundle:nil];
_menuTBC.view.frame = self.view.frame;
And in favotiteVC navigation look's good, and all other's 2 navigations has no spacing from status bar
P.S
First of all, I added my UITabBarController as a child to UIViewController. The first UINavigationController from UITabBarController has right frame (0,20,width,height) , but others 2 UINavigationsControllers, has wrong frame (0,0,width, height). I think they don't have status bar, and I checked that method -prefersStatusBarHidden isn't call from all UIViewControllers which contains in UITabBarController

UINavigationBar with UISegmentedControl partially covers childViews

I have read many other threads on this and the Apple docs, but haven't found a solution yet for my particular problem.
My app uses a UITabBarController as the rootViewController, and in one of the tabs I have a UISegmentedControl in the navigationBar to switch between three child UITableViewControllers.
(In the real app two of the childVCs are a custom UIViewController, I'm just using three UITableViewControllers for the sample app).
The segmentedControl setup and the switching all works fine. The thing that goes wrong is that only the first UITableViewController is shown correctly. For the second and third one, part of the first cell is hidden under the navigationBar. When I click through all three, the first one is still ok.
I have made a little sample app to show what's going on, using very bright colors for demonstration purposes: https://www.dropbox.com/s/7pfutvn5jba6rva/SegmentedControlVC.zip?dl=0
Here is also some code (I'm not using storyboards):
// AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
FirstViewController *fvc = [[FirstViewController alloc] init];
UINavigationController *firstNavigationController = [[UINavigationController alloc] initWithRootViewController: fvc];
SecondViewController *svc = [[SecondViewController alloc] init];
UINavigationController *secondNavigationController = [[UINavigationController alloc] initWithRootViewController: svc];
// Initialize tab bar controller, add tabs controllers
UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = #[firstNavigationController, secondNavigationController];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
// FirstViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.title = #"One";
self.view.backgroundColor = [UIColor orangeColor];
UITableViewController *vc1 = [[UITableViewController alloc] init];
UITableViewController *vc2 = [[UITableViewController alloc] init];
UITableViewController *vc3 = [[UITableViewController alloc] init];
vc1.view.backgroundColor = [UIColor redColor];
vc2.view.backgroundColor = [UIColor blueColor];
vc3.view.backgroundColor = [UIColor greenColor];
self.viewControllers = #[vc1, vc2, vc3];
self.segmentTitles = #[#"Red", #"Blue", #"Green"];
self.segmentedControl = [[UISegmentedControl alloc] initWithItems: self.segmentTitles];
[self.segmentedControl addTarget: self
action: #selector(segmentClicked:)
forControlEvents: UIControlEventValueChanged];
self.navigationItem.titleView = self.segmentedControl;
self.segmentedControl.selectedSegmentIndex = 0;
// set the first child vc:
UIViewController *vc = self.viewControllers[0];
[self addChildViewController: vc];
vc.view.frame = self.view.bounds;
[self.view addSubview: vc.view];
self.currentVC = vc;
}
- (void)segmentClicked:(id)sender
{
if (sender == self.segmentedControl)
{
NSUInteger index = self.segmentedControl.selectedSegmentIndex;
[self loadViewController: self.viewControllers[index]];
}
}
- (void)loadViewController:(UIViewController *)vc
{
[self addChildViewController: vc];
[self transitionFromViewController: self.currentVC
toViewController: vc
duration: 1.0
options: UIViewAnimationOptionTransitionFlipFromBottom
animations: ^{
[self.currentVC.view removeFromSuperview];
vc.view.frame = self.view.bounds;
[self.view addSubview: vc.view];
} completion: ^(BOOL finished) {
[vc didMoveToParentViewController: self];
[self.currentVC removeFromParentViewController];
self.currentVC = vc;
}
];
}
So obviously my question is, why does this happen, and what can I do to fix it?
Edit: adding screenshots.
EDIT: Based on the answer below I changed the code in the animation block to:
[self.currentVC.view removeFromSuperview];
if ([vc.view isKindOfClass: [UIScrollView class]])
{
UIEdgeInsets edgeInsets = UIEdgeInsetsMake(self.topLayoutGuide.length, 0, self.bottomLayoutGuide.length, 0);
[UIView performWithoutAnimation: ^{
vc.view.frame = self.view.bounds;
((UIScrollView *)vc.view).contentInset = edgeInsets;
((UIScrollView *)vc.view).scrollIndicatorInsets = edgeInsets;
}];
}
else
{
vc.view.frame = self.view.bounds;
}
[self.view addSubview: vc.view];
Now it works. I'm going to try this with a custom UIViewController as well.
The issue is that you do not set the correct content inset to each table view. The system attempts to do it for you, but I guess your setup is too complex for it, and it only does it for the first tableview that is loaded in viewDidLoad. In your loadViewController: method, when replacing the currently displayed view, make sure to set both the contentInset and scrollIndicatorInsets to the values of the previous view. I think the system will manage to set the correct insets later, in case you rotate to landscape. Try it. If it doesn't, you will need to do it on your own in viewDidLayoutSubviews.

Call method before SWRevealViewController is shown

I am using the SWRevealViewController plugins, it works great and I can navigate fine around the pages. My issue is that when the menu is being shown you can still interact with objects on the view that called the menu. I want to disable buttons from my view whilst the menu is shown. I am assigning the sidebar button using this code.
_sidebarButton.tintColor = [UIColor colorWithWhite:0.1f alpha:0.9f];
_sidebarButton.target = self.revealViewController;
_sidebarButton.tag=10;
_sidebarButton.action = #selector(revealToggle:);
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
I cannot work out how to call a function in my own class before the revealToggle action is fired. Any suggestions?
In MenuViewController (which is rear viewcontroller) write following:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.revealViewController.frontViewController.view setUserInteractionEnabled:NO];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.revealViewController.frontViewController.view setUserInteractionEnabled:YES];
}
then you can get each subview from this viewcontroller.
for example if frontviewcontroller is UINavigationController, you can do like this:
UINavigationController *navController = (UINavigationController *)self.revealViewController.frontViewController;
UIViewController *rootViewController = [navController.viewControllers firstObject];
NSArray *allViews = [NSArray arrayWithArray:(NSArray *)[rootViewController.view subviews]];

UINavigationController, how to hide tabbar in second level viewController then show tabbar in third level viewController

here is a piece of my code, but in this way, when I push the third level view controller, the tabbar won't show.
//at first level
SecondLevelViewController *_2vc = [[SecondLevelViewController alloc]initWithNibName:#"SecondLevelViewController" bundle:nil];
_2vc.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:_2vc animated:YES];
//at second level
ThirdLevelViewController *_3vc = [[ThirdLevelViewController alloc]initWithNibName:#"ThirdLevelViewController" bundle:nil];
_3vc.hidesBottomBarWhenPushed = NO;
[self.navigationController pushViewController:_3vc animated:YES];
// Load the view
AddViewController *aController = [[AddViewController alloc] init];
// Set the view title
aController.title = #"Add View";
// hide tabbar
aController.hidesBottomBarWhenPushed = YES;
// add it to stack.
[[self navigationController] pushViewController:aController animated:YES];
-(void)viewWillAppear: (BOOL)animated
{
[super viewWillAppear:animated];
[self.tabBarController.tabBar setHidden:YES];
}
-(void)viewWillDisappear: (BOOL)animated
{
[super viewWillDisappear:animated];
[self.tabBarController.tabBar setHidden:NO];
}
Instead of setting the values of hidesBottomBarWhenPushed when you initialise the view controllers, you should instead handle the hiding mechanism in the -(void)viewWillAppear:(BOOL)animated in the view controllers instead.
An example of this implementation would be:
In SecondLevelViewController.m
-(void)viewWillAppear:(BOOL)animated
{
[_bottomBar setHidden:YES];
}
In ThirdLevelViewController.m
-(void)viewWillAppear:(BOOL)animated
{
[_bottomBar setHidden:NO];
}

Resources