how do i pass a value to a table view controller that has a navigation controller?
i have code to push the new view controller and make it active but no way of passing a value to the table view.
UIViewController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:identifier];
the problem is that i dragged a navigation controller onto the storyboard and it came attached to a tableview. i linked that tableview to my custom tableview class. When i instantiate the view controller from the name "nav", which is the storyboard id of the navigation controller, i get the navigation controller as the view controller being instantiated (newTopViewController); so how do pass a value from where i instantiate the view to the tableview controller?
I know this is already answered (nicely done ttarules), but I thought I'd pass along some extra comments. It's very common to have some type of view controller embedded in a navigation controller. Wrapping a standard view controller in a navigation controller then doing a modal segue to it, gives you a modal scene, with a nice nav bar to put buttons in, etc. Also on the iPad, replace segues can commonly use navigation controllers. It's all about how you design things, but if you know how the controllers stack up and how to easily reference them, you will have more design options. Here is a snippet you can use in your prepare for segue method to easily detect it.
if ([segue.destinationViewController isKindOfClass:[UINavigationController class]]) {
//note: have to get reference to next vc through nav controller
self.nextViewController = [[(UINavigationController*)segue.destinationViewController viewControllers]lastObject];
}
else {
self.nextViewController = segue.destinationViewController;
}
You should pass it inside prepareForSegue if your already going to be segueing to that VC.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"whateverYourSegueIsCalled"])
{
YourTableViewController *tableView=(YourTableViewController*)segue.destinationViewController;
tableView.anyPublicProperty = yourValue;
}
}
EDIT:
Okay so since you actually just have the tableView embedded, you simply need to access the viewControllers property of the navigationViewController..
So it will be something like this inside your navigationViewController class:
YourTableViewController *tableView = (YourTableViewController*)[self.navigationController.viewControllers objectAtIndex:0];
tableView.yourPublicProperty = whateverValueYouWant;
-Your tableView will be the object at index 0 unless you have other VC's also embedded..So you can just print out your vc's and then figure it out from there if you do.
Related
I have view which contains a collection view. I have added this collection view programatically (in viewDidLoad) - so that is not on the storyboard. This collection view contains several cells. When a user clicks on one of the cells in the collection view, I want to segue to a different view controller (that I plan to add on the storyboard). My question is - since the collection view is not on storyboard, how can I segue out of that? Or is there other way to accomplish that.
Some updates to the original question above:
In Parent View Controller, I do the following:
//Layout for the collection view
CDLayout *cdLayout = [[CDLayout alloc] initWithItemSize:CGSizeMake(cardWidth, cardHeight) withItemInsets:UIEdgeInsetsMake(topInset, leftInset, bottomInset, rightInset) withInterItemSpacingX:8.0f withTopMargin:margin withLeftMargin:margin withBottomMargin:margin withRightMargin:margin shouldRotate:NO];
//This is the collection view controller
CDLineLayoutViewController *cdLineVC = [[CDLineLayoutViewController alloc] initWithCollectionViewLayout:cdLayout withItemCount:12 ];
// add the collection view controller to self - the parent
[self addChildViewController:cdLineVC];
[cdLineVC didMoveToParentViewController:self];
// add collectionView as a subview
[self.view addSubview:cdLineVC.collectionView];
The collectionView has 12 cards. When a user clicks on one of the cards I want to move to another view controller.
As you can see the collection view is not on the storyboard. So, is there a way to create a segue?
BTW, one option is what Taseen suggested below. I tried that and it is working. But as I understand it is not actually a "segue."
Can you please show us any code you have written
What i have understood from your question is that you have added collection view in viewDidLoad. and i believe you have set the delegate of collection view to self, So in
didSelectItemAtIndexPath method you can write this code
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
//From indexpath.item, you know which cell was clicked
//using switch method
switch (indexPath.item) {
case 0:
//You Can push the view controller from here
//You need to import the header file of that View controller
DestinationViewController *destinationView;
//if the self controller in which the collection view is shown is embedded in Navigation controller,
//you can push using
[self.navigationController pushViewController:destinationView animated:YES];
//if it is not embedded, use modal segue
[self.modalViewController presentModalViewController:destinationView animated:YES];
break;
default:
break;
}
}
EDIT: The segue you will create on the storyboard from your ParentViewController to DestinationController will have segueIdentifier property. like shown below
then in didSelectItemAtIndexPath instead of pushing the controller you can use this code
[self performSegueWithIdentifier:#"collectionViewSegue" sender:self];
you can also configure the destination view controller using prepareForSegue method..
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
DestinationViewController *targetVC = (DestinationViewCOntroller *)segue.destinationViewController;
//if you pass anything you can do it here
//if to set any public variable for example image for the imageview
targetVC.cardImageView.image = [UIImage imageNamed:#"queen.png"];
}
This method will be in your parent controller.
Create a new segue by ctrl-click on the initial viewController and drag to the destination viewController. Don't forget to set the segue identifier.
than overwrite the -(void)performSegueWithIdentifier:(NSString *)identifier sender:(id)sender method.
I'm trying to select one of my UINavigationControllers in the UITabBar.viewControllers array.
I previously tried it with setting the UITabbarController.selectedIndex, but the Apple documentation says:
"To select the More navigation controller itself, you must change the value of the selectedViewController property instead."
AppDelegate *appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
UINavigationController *navController = [appDelegate.objTabBarController.viewControllers objectAtIndex:5];
[appDelegate.objTabBarController setSelectedViewController:navController];
Doing so is fine but when I change back to the MoreViewController's list view, the icon on the left side is gone and won't come back.
Everything ok, when selecting it with the finger.
Bug when selecting programmatically -> image is gone
Any suggestions what I'm doing wrong?
Best regards,
Steve
Selecting the More Navigation Controller
To select the moreNavigationController, you must set the selectedViewController:
self.tabBarController.selectedViewController = self.tabBarController.moreNavigationController;
The reason for that is simple: The moreNavigationController is not inside the viewControllers of the tab bar controller, so it can't be selected by index.
To select one of the "more" controllers directly, you can either set the selectedViewController property:
self.tabBarController.selectedViewController = viewController5;
Or you can set the selectedIndex:
self.tabBarController.selectedIndex = 5;
Fixing the Disappearing Tab Bar Image
The disappearing tab bar image is caused by using a navigation controller (for the settings) inside a navigation controller (the moreNavigationController generated by the tab bar controller). To fix it, there are two solutions:
Don't add navigation controllers for the more section, but add the controllers directly. The controller structure would look like this, assuming the controllers in all tabs need navigation:
tabBarController
+ navigationController
+ viewController0
+ navigationController
+ viewController1
+ navigationController
+ viewController2
+ navigationController
+ viewController3
+ viewController4
+ viewController5
Set the tabBarItem of the settings controller on its navigation controller (you only need to do this once):
UINavigationController *settingsNavigationController = [appDelegate.objTabBarController objectAtIndex:5];
UIViewController *settingsRootController = settingsNavigationController.viewControllers[0];
settingsNavigationController.tabBarItem = settingsRootController.tabBarItem;
I ran into this same problem. It seems that the navigation controller was somehow losing track of the view controller. In my case, the navigation controller whose image was disappearing was at index 7 in the tabBarController. The navigation controller was supposed to contain a viewController of class SettingsViewController. But sometimes it lost it.
To fix it, I had to add code to two classes -- the app delegate and SettingsViewController. In the app delegate:
-(void) fixSettingsNavigationController {
UITabBarController* tab = self.tabBarController;
NSArray* vcs = tab.viewControllers;
NSInteger nVCs = vcs.count;
if (nVCs > 7) {
UIViewController* settingsContainer = vcs[7];
UINavigationController* settingsContainerNav = (UINavigationController*)settingsContainer;
if ([settingsContainerNav isKindOfClass: [UINavigationController class]]) {
NSArray* settingsNavVCs = settingsContainerNav.viewControllers;
NSInteger count = settingsNavVCs.count;
SettingsViewController* svc = self.settingsViewController;
if (!count) {
// The container navigation controller has lost track of the settings view controller.
settingsContainerNav.viewControllers = [NSArray arrayWithObject:svc];
}
}
}
}
And in SettingsViewController:
-(void) viewWillDisappear:(BOOL)animated {
MyAppDelegate* appDel = [[UIApplication sharedApplication] delegate];
[appDel fixSettingsNavigationController];
[super viewWillDisappear: animated];
}
I ran to the very similar situation, where I want to select a View controller inside MoreViewController programmatically.
As you said in your question, apple don't allow selecting a view controller that is inside MoreViewController (Or not visible in tabbar).
In my case, I don't need default "More" features of reordering tabs in tabbar.
So, I did following things
Created a UITableViewControlelr as my 5th tab, set its Title to more and custom image (Similar to default more image).
In my UITableViewController I listed items that corresponds to ViewControllers. Tapping on which show respective view controller.
When i need to show any view controller that is inside my UITableViewController programatically, i simply set a flag and push my UITableViewController, and in viewDidAppear method of my UITableViewController push desired view controller.
This will also show back button on programatically opened view to list of MoreViewController
viewWillAppear is called both when going to the view and when coming back to the view from other views.
I want to select(highlight) and fade-out a cell only when coming back from other views.
Is there a delegate method to do this?
I'm using UINavigationViewController.
If you're on iOS 5, you can use these new properties:
These four methods can be used in a view controller's appearance
callbacks to determine if it is being presented, dismissed, or added
or removed as a child view controller. For example, a view controller
can check if it is disappearing because it was dismissed or popped
by asking itself in its viewWillDisappear: method by checking the
expression ([self isDismissing] || [self
isMovingFromParentViewController]).
- (BOOL)isBeingPresented __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0);
- (BOOL)isBeingDismissed __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0);
- (BOOL)isMovingToParentViewController __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0);
- (BOOL)isMovingFromParentViewController __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0);
In your code:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (!(self.isMovingToParentViewController || self.isBeingPresented))
{
// animate
}
}
EDIT:
If you're using a UITableViewController, setting the property -clearsSelectionOnViewWillAppear to YES will do this for you. You only have to do it manually if you're using a regular UIViewController with a UITableView subview.
If you are targeting iOS 5, you can use [self isBeingPresented] and [self isBeingDismissed] to determine if the view controller is being added or removed from the nav controller.
I'm also suspecting that you could improve the logic of when you select/deselect the cell in your table view such that it doesn't matter whether the view controller is coming or going.
The usual way to do it is this: when someone selects a row in the table view in view controller A, it gets selected/highlighted and you push a new view controller B. When view controller B is dismissed, you animate the deselection of the table view row in viewDidAppear (so the user can see it fading out) in view controller A. You wouldn't worry about whether view controller A has just appeared or is re-appearing, because there would only be a selected table view cell in the appropriate case.
viewWillAppear is getting called when the view appears
after the viewDidLoad
after you dismiss or pull a view controller
You could change the viewWillAppear to the following
- (void) viewWillAppear:(BOOL)animated
{
static BOOL firstTime = YES;
if (!firstTime)
{
//Do your alpha animation
}
firstTime = NO;
}
In your UINav Controller you could create a "lastView" property and have each of your view controllers (that are controlled by your UINav Controller) set this property on "viewWillAppear"... in your target view... the one you want to do the highlighting and fading you could check this property of the UINav Controller and see if it's NIL or not.
That's just one way to do it. This wouldn't work if you pop up a modal or the like.
I am currently trying to copy an array I have to a new view that I am creating programmatically. I actually have found how to do this with normal navigation controller syntax. My issue is I'm using the new storyboard and I don't know the syntax to do the same thing. Here is the code I have..
CustomerListViewController *second = [[CustomerListViewController alloc] initWithNibName:#"CustomerListViewController" bundle: nil];
[second setValue:customerList.list];
// [self.navigationController pushViewController:second animated:YES];
[self performSegueWithIdentifier:#"LoginSegue" sender:self];
as you can see, I am programmatically creating the second view controller and storing the local array customerList.List to the created view controller's array variable. The next step is to open the new created view. The line commented out is the syntax to open the view under a navigation controller. The line below is the storyboard way, but minus specifying the view I created. I need to know the syntax for the storyboard to do the same thing as the navigation controller.
It does not make sense to create your own instance of CustomerListViewController here if you're using segues. The segue itself will create the view controller from the storyboard and the instance you have created here will do nothing.
Instead, just call performSegueWithIdentifier:sender: here. Then implement the prepareForSegue:sender: method like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"LoginSegue"]) {
CustomerListViewController *destinationController = (CustomerListViewController *)segue.destinationViewController;
[destinationController setValue:customerList.list];
}
}
heres my issue, I have a tabbar as the root controller, I then have tabs which are navigation controllers. ( all this is done in Interface Builder )
each navigation controller has a view controller. one of these view controllers have a table view.
on the navigation controller of this table view, I want a item button which reloads the table view.
i know to use reloadData.
I have linked the item button up to a IBAction in the view controller of the navigation controller by making a new NSObject in the mainWindow.xib pointing to this view controller. in the view controller I have this IBAction
-(IBAction)reloadTable:(id)sender
{
NSLog(#"RELOADDDDING");
[self.tableViewIB reloadData];
}
The NSlog is displayed, but the table is not reloading.
I have tried with and without the self.
I had the exact same setup with the exact same issue. Below is how I fixed it. Put this code in the view controller with the Table.
- (void)viewWillAppear:(BOOL)animated {
//reload table now that we have a good array to show
[self.view reloadData];
[super viewWillAppear:animated];
}
Updated in response to your comment
Add this code to the action of your button being pushed
//button was pushed code
TableViewController * vc = (TableViewController *)[[TableViewController alloc] init];
//this tableview should be named whatever you have your table named as.
[vc.tableView reloadData];
[vc release];
I had asked the exact same question few minutes back - - - This might be a simple question. HELP with Resetting UITableViewCells
Just do this !
Assign TableView as a property.
Reload it in ViewWillAppear