How to: Save position/order of UITabBarItems after the have been reordered
Okay, I have searched around for a answer to this question and so far come up with no开发者_Python百科ne.
Heres my question: I am using the default TabBarApplication provided by Apple. And since I have created 10 tabs it is using the default reordering process. So after I reorder the tabs and quit the app I want to save the position of the tabs to be restored when the app relaunches. How would I do this? Code samples appreciated!
The tabItems are stored in an array. You could do something like this (pseudo-code):
* myArray = [tabBar tabBarItems];
* itemNameArray = [[NSMutableArray new] autorelease];
* for (UITabBarItem *item in myArray)
* NSString *itemName = [item title];
* [itemNameArray addObject: itemName];
* [[NSUserDefaults standardUserDefaults] setObject: itemNameArray forKey: @"TabItemNames"]
Then, at app restart, load the array and set-up the tab items in the right order.
I found this a little confusing as well. Hopefully my research will help others out...
I think the confusion comes from the fact that UITabBar.items returns an array of just the 4 items visible in the current tabBar. When apple says that you shouldn't mess with the tabBar object, this is what they mean.
The way you read the order of items (and update the order of items) is through the viewControllers parameter of the UITabBarController.
So code would look something like (this is in a class which overrides UITabBarController):
- (UIViewController *)vcWithTabBarTitle:(NSString *)name
{
NSLog(@"looking for UIViewController with tabBarItem.title = %@", name);
for (UIViewController *item in self.viewControllers)
{
if ([item.tabBarItem.title isEqualToString:name])
return item;
}
return nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSArray *itemNames = [userDefaults objectForKey:@"viewControllersOrder"]
if (itemNames != nil && itemNames.count > 0)
{
NSMutableArray *items = [NSMutableArray arrayWithCapacity:self.viewControllers.count];
for (NSString *itemName in itemNames)
{
[items addObject:[self vcWithTabBarTitle:itemName]];
}
[self setViewControllers:items];
}
}
- (void)tabBarController:(UITabBarController *)tabBarController didEndCustomizingViewControllers:(NSArray *)viewControllers changed:(BOOL)changed
{
if (changed)
{
NSMutableArray *itemNames = [[NSMutableArray alloc] initWithCapacity:viewControllers.count];
for (UIViewController *item in viewControllers)
{
if (item.tabBarItem.title != nil)
{
[itemNames addObject:item.tabBarItem.title];
}
}
[userDefaults setObject:itemNames forKey:@"viewControllersOrder"];
}
}
I know this is an old question, but I felt like posting this as it's what I found when looking up how to do this.
So the other answers (as of me writing this) are not incorrect. However they will break instantly when you introduce localisation or have a navigation item that changes it's title dynamically, both of which are very possible.
I ended up using the restoreIdentifier that you can either set in code or in IB to any view controller (or subclass there of).
NOTE: This is implemented within a subclass of UITabBarController.
Save Tab Bar View Controllers order
NSMutableArray *tabBarVCIDs = [NSMutableArray new];
for (UIViewController *viewController in [self viewControllers])
[tabBarVCIDs addObject:[viewController rootRestorationIdentifier]];
[[NSUserDefaults standardUserDefaults] setObject:tabBarVCIDs forKey:@"tabBarVCIDs"];
[[NSUserDefaults standardUserDefaults] synchronize];
Load Tab Bar Items Order
NSMutableArray *tabBarVCIDs = [[NSUserDefaults standardUserDefaults] objectForKey:@"tabBarVCIDs"];
if (tabBarVCIDs)
{
NSMutableArray *viewControllers = [NSMutableArray new];
for (NSString *vcID in tabBarVCIDs)
{
for (UIViewController *viewController in [self viewControllers])
{
if ([[viewController rootRestorationIdentifier] isEqualToString:vcID])
{
[viewControllers addObject:viewController];
break;
}
}
}
[self setViewControllers:viewControllers];
}
rootRestorationIdentifier
is a method I put into a category to get the correct restoration identifier even when a view controller is within a navigation controller or split view controller (this is useful with universal apps that might have slightly different layouts).
- (NSString *)rootRestorationIdentifier
{
if ([self isKindOfClass:[UINavigationController class]] || [self isKindOfClass:[UISplitViewController class]])
{
__weak UIViewController *rootVC = [[(UINavigationController *)self viewControllers] firstObject];
return [rootVC rootRestorationIdentifier];
}
return [self restorationIdentifier];
}
You could also use NSPredicate
instead of nested for loops, but it's probably not necessary.
精彩评论