如何:在重新排序后保存 UITabBarItems 的位置/顺序

发布于 2024-12-06 23:42:29 字数 183 浏览 0 评论 0原文

好吧,我已经四处寻找这个问题的答案,但到目前为止还没有找到答案。

这是我的问题:我正在使用 Apple 提供的默认 TabBarApplication。由于我创建了 10 个选项卡,因此它使用默认的重新排序过程。因此,在我重新排序选项卡并退出应用程序后,我想保存选项卡的位置,以便在应用程序重新启动时恢复。我该怎么做?代码示例表示赞赏!

Okay, I have searched around for a answer to this question and so far come up with none.

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我喜欢麦丽素 2024-12-13 23:42:29

tabItems 存储在一个数组中。您可以执行以下操作(伪代码):

* 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"]

然后,在应用程序重新启动时,加载数组并按正确的顺序设置选项卡项。

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.

眼波传意 2024-12-13 23:42:29

我也发现这有点令人困惑。希望我的研究能够帮助其他人......

我认为混乱来自于 UITabBar.items 返回一个仅当前 tabBar 中可见的 4 个项目的数组。当苹果说你不应该弄乱 tabBar 对象时,这就是他们的意思。

读取项目顺序(并更新项目顺序)的方式是通过 UITabBarController 的 viewControllers 参数。

所以代码看起来像这样(这是在一个重写 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 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"];
    }
}
镜花水月 2024-12-13 23:42:29

我知道这是一个老问题,但我想发布这个问题,因为这是我在查找如何做到这一点时发现的。

所以其他答案(截至我写这篇文章时)并不是不正确的。然而,当您引入本地化或有一个动态更改其标题的导航项时,它们会立即中断,这两种情况都是很有可能的。

我最终使用了restoreIdentifier,您可以在代码中或在IB 中将其设置为任何视图控制器(或其子类)。

注意:这是在 UITabBarController 的子类中实现的。

保存选项卡栏视图控制器顺序

NSMutableArray *tabBarVCIDs = [NSMutableArray new];
for (UIViewController *viewController in [self viewControllers])
    [tabBarVCIDs addObject:[viewController rootRestorationIdentifier]];

[[NSUserDefaults standardUserDefaults] setObject:tabBarVCIDs forKey:@"tabBarVCIDs"];
[[NSUserDefaults standardUserDefaults] synchronize];

加载选项卡栏项目顺序

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 是我放入类别中的一种方法,即使在视图控制器位于导航控制器或拆分视图控制器内(这对于布局可能略有不同的通用应用程序很有用)。

- (NSString *)rootRestorationIdentifier
{
    if ([self isKindOfClass:[UINavigationController class]] || [self isKindOfClass:[UISplitViewController class]])
    {
        __weak UIViewController *rootVC = [[(UINavigationController *)self viewControllers] firstObject];
    return [rootVC rootRestorationIdentifier];
    }

    return [self restorationIdentifier];
}

您还可以使用 NSPredicate 代替嵌套 for 循环,但这可能没有必要。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文