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.
Related
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.
I have a main view.
From that main view I show a modal view (MV1).
MV1 may show another modal View (MV2).
From MV2, I may show another modal view (MV3).
All that MV are shown animated.
What I want, is to be able to first display (animated) the next modal view (MVx+1) before "killing" the previous one (MVx).
If I dismiss (animated) MVx before showing MVx+1 : MVx+1 does not appear.
If I dismiss (non-animated) MVx before showing MVx+1 : MVx-1 is seen.
If I show MVx+1 before dismissing (non-animated) MVx : MVx+1 does not appear.
How may I do ?
Some code sample would help if you have time, but just a detailed explanation would be enough.
According to the Apple docs, the accepted way to dismiss modal views is by letting the parent controller (i.e., the view controller that created the modal view) do the dismissing. The best way to do this is by setting the parent controller as the delegate of the modal view controller. The idea here is that the modal controller tells its parent that it's ready to be dismissed, and the parent decides what course of action to take from there.
In order to do this, you have to create a delegate protocol for the modal view controller that the parent controller implements. In your case, you can create a protocol at the top of each of your .h files for your modal views to do this (or a single protocol in a separate file if all of the modal views can use the same method for dismissal). For example:
#protocol MYModalViewDelegate <NSObject>
-(void)dismiss;
#end
Next, in each of your modal view controllers, create an instance variable for the delegate:
#interface MYModalViewController1 : UIViewController {
id<MYModalViewDelegate> delegate;
}
When you display a modal view from a current view controller, set the current controller as the delegate.
MYModalViewController1 * mvc1 = [[MYModalViewController1 alloc] initWithNibName:#"MYModalViewController1" bundle:nil];
mvc1.delegate = self;
[self presentModalViewController:mvc1 animated:YES];
[mvc1 release];
When you want to release the current modal controller, have the modal view controller call the appropriate protocol method on its delegate:
[self.delegate dismiss];
Now, the delegate can handle where to go next. In your case, you can close MV2 automatically when MV3 closes by calling [self.delegate dismiss] in MV3, then implement dismiss in MV2 as:
-(void)dismiss {
[self dismissModalViewControllerAnimated:YES];
[self.delegate dismiss];
}
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
I want to hide an image when the tabBar button is pressed.I have
self.tabBarController.delegate = self;
in my app delegate and the code below is located in my view controller's .m file . but it doesn't work . Can anyone help pls ?
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
if (viewController.tabBarController == nil)
{
img.hidden = YES;
NSLog(#"Tab Bar Button");
}
}
Do you know that
In versions of iOS prior to version
3.0, this method is called only when the selected view controller actually
changes. In other words, it is not
called when the same view controller
is selected.
In addition to this, make sure you are hiding the imageView that contains the image.
UPDATE
Get the tabBarController instance in the view controller and make its delegate the view controller. Then you can call this method in the view controller.
give name for the tabbarcontroller and then set the delegate for that.If my suggestion not useful,then ask me freely
How can I manage the user selection on the "more" view of a UITabBar? I have this code to manage the UITabBarItems selections:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
if (!(viewController == tabBarController.moreNavigationController)) {
int index = tabBarController.selectedIndex;
[[DataManager sharedInstance] setCurrentTabbarIndex:index];
}
}
It works fine for the visible UITabBarItems, but when the user select some item from the "more" view I never get informed about that. Is there some way to catch the user item selection of the "more" view? Thanks!
The "more" view of a UITabBarController is handled separately from the other views. Apple's discussion on this subject says the following:
[The 'moreNavigationController'] property always contains a valid More navigation controller, even if a More button is not displayed on the screen. You can use the value of this property to select the More navigation controller in the tab bar interface or to compare it against the currently selected view controller.
Do not add the object stored in this property to your tab bar interface manually. The More controller is displayed automatically by the tab bar controller as it is needed. You must also not look for the More navigation controller in the array of view controllers stored in the viewControllers property. The tab bar controller does not include the More navigation controller in that array of objects.
Judging from that I would think that you can do something like:
int index = tabBarController.selectedIndex;
if (tabBarController.selectedViewController ==
tabBarController.moreNavigationController) {
index = -1; //assign some placeholder index for the "More" controller
}
A very late answer for a very old question, but here it is anyway, in case someone stumbles upon this.
The solution is to assign yourself as the delegate of the "more" navigation controller. You already have a class that adopts the UITabBarControllerDelegate protocol, so the .h file might look like this:
#interface MyDelegate : NSObject <UITabBarControllerDelegate, UINavigationControllerDelegate>
{
}
Wherever you are assigning your class as delegate, do this:
- (void) assignDelegate:(MyDelegate)myDelegate toTabBarController:(UITabBarController*)tabBarController
{
tabBarController.delegate = myDelegate;
tabBarController.moreNavigationController.delegate = myDelegate;
}
And finally, in your delegate class add this method:
- (void) navigationController:(UINavigationController*)navigationController didShowViewController:(UIViewController*)viewController animated:(BOOL)animated
{
// add code to handle the event
}
Note that none of your delegate methods are invoked when you change tabs programmatically.
The best approach I've found for this problem is to become the delegate for the UITableView which is the topViewController in the UITabBarController.moreViewController.
Implementing the didSelectRowAtIndexPath should solve the problem!
The best (and most secure) implementation for this is described by Stuart Sharpe in his blog: http://initwithstyle.net/2014/02/making-more-of-the-more-view/
Whatever view is being selected will receive viewWillAppear:animated:
Provide this in every view that's controlled by your tab bar, and you can thus extract the identity of the user's selection even when made from a "More" controller.
You can save the tab bar state right in this method, or you can provide your views with a reference back to the tab bar and notify it.