如何:在UITabBarController中自定义选项卡时保存选项卡的顺序

时间:2010-01-09 17:20:30

标签: iphone uitabbarcontroller

我在查找除了如何保存UITabBarController的Tab键顺序的文档之外的任何其他信息时遇到问题,以便保存用户的自定义以便下次启动应用程序。我在网上搜索过,但一直找不到任何博文或文章,这些帖子或文章都是通过正确的代码来完成的。

我意识到我必须使用UITabBarController的委托方法(didEndCustomizingViewControllers :),但我不确定在保存用户想要标签的顺序的状态方面我最好如何处理持久性。

有人可以发布一些代码,指出我正确的方向,或者你有一个保存链接的链接? :)

由于

8 个答案:

答案 0 :(得分:18)

就您要求提供一些示例代码而言,我将在此处发布我在应用程序中处理相同任务的方式。

快速介绍:我使用的是NIB文件来存储初始UITabBarController状态,并且我的选项卡彼此不同我只是为分配给每个UITabBarItem填充的UIViewController对象定义了标记变量在我的UITabBarController。为了能够准确地跟踪上次选择的标签(包括“更多”标签),我已经为{more}的UITabBarControllerDelegate UITabBarController及其更多导航控制器的UINavigationControllerDelegate实施了以下方法。他们在这里:

#pragma mark UINavigationControllerDelegate

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    [[NSUserDefaults standardUserDefaults] setInteger:mainTabBarController.selectedIndex forKey:@"mainTabBarControllerSelectedIndex"];
}

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    [[NSUserDefaults standardUserDefaults] setInteger:mainTabBarController.selectedIndex forKey:@"mainTabBarControllerSelectedIndex"];
}

#pragma mark UITabBarControllerDelegate

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
    [[NSUserDefaults standardUserDefaults] setInteger:tabBarController.selectedIndex forKey:@"mainTabBarControllerSelectedIndex"];
}

以下是保存标签顺序的代码:

#pragma mark UITabBarControllerDelegate

- (void)tabBarController:(UITabBarController *)tabBarController didEndCustomizingViewControllers:(NSArray *)viewControllers changed:(BOOL)changed {
    int count = mainTabBarController.viewControllers.count;
    NSMutableArray *savedTabsOrderArray = [[NSMutableArray alloc] initWithCapacity:count];
    for (int i = 0; i < count; i ++) {
        [savedTabsOrderArray addObject:[NSNumber numberWithInt:[[[mainTabBarController.viewControllers objectAtIndex:i] tabBarItem] tag]]];
    }
    [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithArray:savedTabsOrderArray] forKey:@"tabBarTabsOrder"];
    [savedTabsOrderArray release];
}

正如您所见,我一直在NSUserDefaults的数组中存储选项卡索引的顺序。

在应用程序的applicationDidFinishLaunching:方法启动时,我使用以下代码对UIViewControllers进行了重新排序:

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    mainTabBarController.delegate = self;

    int count = mainTabBarController.viewControllers.count;
    NSArray *savedTabsOrderArray = [[userDefaults arrayForKey:@"tabBarTabsOrder"] retain];
    if (savedTabsOrderArray.count == count) {
        BOOL needsReordering = NO;

        NSMutableDictionary *tabsOrderDictionary = [[NSMutableDictionary alloc] initWithCapacity:count];
        for (int i = 0; i < count; i ++) {
            NSNumber *tag = [[NSNumber alloc] initWithInt:[[[mainTabBarController.viewControllers objectAtIndex:i] tabBarItem] tag]];
            [tabsOrderDictionary setObject:[NSNumber numberWithInt:i] forKey:[tag stringValue]];

        if (!needsReordering && ![(NSNumber *)[savedTabsOrderArray objectAtIndex:i] isEqualToNumber:tag]) {
                needsReordering = YES;
            }
        }

        if (needsReordering) {
            NSMutableArray *tabsViewControllers = [[NSMutableArray alloc] initWithCapacity:count];
            for (int i = 0; i < count; i ++) {
                [tabsViewControllers addObject:[mainTabBarController.viewControllers objectAtIndex:
                                                [(NSNumber *)[tabsOrderDictionary objectForKey:
                                                              [(NSNumber *)[savedTabsOrderArray objectAtIndex:i] stringValue]] intValue]]];
            }
            [tabsOrderDictionary release];

            mainTabBarController.viewControllers = [NSArray arrayWithArray:tabsViewControllers];
            [tabsViewControllers release];
        }
    }
    [savedTabsOrderArray release];

    if ([userDefaults integerForKey:@"mainTabBarControllerSelectedIndex"]) {
        if ([userDefaults integerForKey:@"mainTabBarControllerSelectedIndex"] == 2147483647) {
            mainTabBarController.selectedViewController = mainTabBarController.moreNavigationController;
        }
        else {
            mainTabBarController.selectedIndex = [userDefaults integerForKey:@"mainTabBarControllerSelectedIndex"];
        }
    }

    mainTabBarController.moreNavigationController.delegate = self;

    [window addSubview:mainTabBarController.view];
}

这很棘手,可能看起来很奇怪,但不要忘记我的UITabBarController是在nib文件中完全创建的。如果您以编程方式构建它,您可能只是按照保存的顺序执行相同操作。

P.S。:并且不要忘记在您的应用终止时同步NSUserDefaults

- (void)applicationWillTerminate:(UIApplication *)application {
    [[NSUserDefaults standardUserDefaults] synchronize];
}

我希望这会有所帮助。如果不清楚,请做出评论并询问。

答案 1 :(得分:15)

首先我投了上一个答案,但后来我注意到它的复杂程度是多么的复杂。它可以而且应该简化。

- (void)applicationDidFinishLaunching:(UIApplication *)application {

    NSArray *initialViewControllers = [NSArray arrayWithArray:self.tabBarController.viewControllers];
    NSArray *tabBarOrder = [[AppDelegate sharedSettingsService] tabBarOrder];
    if (tabBarOrder) {
        NSMutableArray *newViewControllers = [NSMutableArray arrayWithCapacity:initialViewControllers.count];
        for (NSNumber *tabBarNumber in tabBarOrder) {
            NSUInteger tabBarIndex = [tabBarNumber unsignedIntegerValue];
            [newViewControllers addObject:[initialViewControllers objectAtIndex:tabBarIndex]];
        }
        self.tabBarController.viewControllers = newViewControllers;
    }

    NSInteger tabBarSelectedIndex = [[AppDelegate sharedSettingsService] tabBarSelectedIndex];
    if (NSIntegerMax == tabBarSelectedIndex) {
        self.tabBarController.selectedViewController = self.tabBarController.moreNavigationController;
    } else {
        self.tabBarController.selectedIndex = tabBarSelectedIndex;
    }

    /* Add the tab bar controller's current view as a subview of the window. */
    [self.window addSubview:self.tabBarController.view];
}

- (void)applicationWillTerminate:(UIApplication *)application {

    NSInteger tabBarSelectedIndex = self.tabBarController.selectedIndex;
    [[AppDelegate sharedSettingsService] setTabBarSelectedIndex:tabBarSelectedIndex];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

- (void)tabBarController:(UITabBarController *)tabBarController didEndCustomizingViewControllers:(NSArray *)viewControllers changed:(BOOL)changed {

        NSUInteger count = tabBarController.viewControllers.count;
        NSMutableArray *tabOrderArray = [[NSMutableArray alloc] initWithCapacity:count];
        for (UIViewController *viewController in viewControllers) {

            NSInteger tag = viewController.tabBarItem.tag;
            [tabOrderArray addObject:[NSNumber numberWithInteger:tag]];
        }

        [[AppDelegate sharedSettingsService] setTabBarOrder:[NSArray arrayWithArray:tabOrderArray]];
        [tabOrderArray release];
    }

所有这些都发生在AppDelegate中。在Interface Builder中将UITabBarController的委托设置为AppDelegate实例。 sharedSettingsService是为我保留数据的原因。基本上它可以是NSUserDefaults前端或任何你喜欢的东西(例如CoreData)。所以一切都很简单,Interface Builder在这里提供帮助,而不是让事情变得更复杂。

答案 2 :(得分:3)

也许是比赛的后期,但是在学校学习Swift的时间不到两个月,而且这个时间可能超过15个小时,因为我无法在interwebz上找到合适的解释。

这是Swift中的解决方案

  1. 将所有tabItem标记为1,从1开始。您可以在每个单独的视图中执行此操作。如果您有六个视图,那么他们的tabItems在这种情况下将具有唯一的编号,每个视图的范围在1到6之间。

  2. UITabBarControllerDelegate 添加到所有ViewControllers&#39;类,这样你就可以使用后面第5点中解释的功能。

    class FirstViewController: UIViewController, UITabBarControllerDelegate {
    
  3. 全局添加以下变量(在上面的代码之后,作为示例),这样您就可以从手机中的任何函数本地保存变量。

    let defaults = NSUserDefaults.standardUserDefaults()
    
  4. 将tabBarController委托给视图,以便视图可以更新tabBarController的任何更改。将以下内容放入 viewDidLoad()

    tabBarController!.delegate = self
    
  5. 实现以下代码。当用户编辑选项卡视图时,将激活此选项。代码的作用是按照它们所在的顺序(在用户更改之后)获取 [ViewControllers] 标签,并将其保存在手机本地。第一个viewController标签在变量&#34; 0&#34;中保存为整数,第二个标签保存在名为&#34; 1&#34;的变量中,依此类推。

    func tabBarController(tabBarController: UITabBarController, didEndCustomizingViewControllers viewControllers: [UIViewController], changed: Bool) {
        if (changed) {
            print("New tab order:")
            for (var i=0; i<viewControllers.count; i++) {
                defaults.setInteger(viewControllers[i].tabBarItem.tag, forKey: String(i))
                print("\(i): \(viewControllers[i].tabBarItem.title!) (\(viewControllers[i].tabBarItem.tag))")
            }
        }
    }
    
  6. 打印件会告诉您标签的新顺序。没有什么是你需要的,但我觉得很高兴看到后台发生了什么。所有这些只是为了保存选项卡的顺序。现在,您必须在程序启动时检索它们。

    1. UIViewControl文件切换到 AppDelegate.swift

    2. 最后,在 func应用程序中编写以下内容(应用程序:UIApplication,didFinishLaunchingWithOptions ...您可以在 AppDelegate.swift 的顶部找到。< / p>

      func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
      // Let you read and write to local variables on your phone
      let defaults = NSUserDefaults.standardUserDefaults()
      
      // Getting access to your tabBarController
      let tabBar: UITabBarController = self.window?.rootViewController as! UITabBarController
      
      var junkViewControllers = [UIViewController]()
      
      // returns 0 if not set, hence having the tabItem's tags starting at 1.
      var tagNumber : Int = defaults.integerForKey("0")
      
      if (tagNumber != 0) {
          for (var i=0; i<tabBar.viewControllers?.count; i++) {
              // the tags are between 1-6 but the order of the
              // viewControllers in the array are between 0-5
              // hence the "-1" below.
              tagNumber = defaults.integerForKey( String(i) ) - 1
              junkViewControllers.append(tabBar.viewControllers![tagNumber])
          }
      
          tabBar.viewControllers = junkViewControllers
      }
      }
      
    3. 值得注意的是,tabBarController包含的所有视图都存储为 tabBarController.viewControllers 中的数组。

      这段代码基本上创建了一个名为 junkViewControllers 的数组。然后,for循环以先前存储的变量的顺序从程序中添加现有的UIViewControllers,基于UIViewControllers&#39;标签。完成所有这些操作后,缩短为 tabBar 的tabBarController将被数组 junkViewController 覆盖。

答案 3 :(得分:1)

我将解释如何以编程方式执行此操作。注意:这是使用ARC,因此您可能需要根据需要插入保留/释放呼叫。

您使用tag的{​​{1}}属性进行排序。对于要添加到UITabBarItem的每个UIViewController,请确保每个UITabBarController都有唯一的tag

- (id)init
{
    self = [super init];
    if (self) {
        self.tabBarItem.tag = 0;
        self.tabBarItem.image = <image>;
        self.tabBarItem.title = <title>;
    }
    return self;
}

大概你只需要为他们的标签使用他们的默认排序顺序,所以无论你拥有什么原始的第一个视图控制器都是0,然后是1,2,3等。

像往常一样在AppDelegate的didFinishLaunchingWithOptions中设置你的UIViewControllers,确保你以“默认顺序”实例化它们。在执行此操作时,将它们添加到NSMutableArray的实例。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{    
    self.tabBarController = [[UITabBarController alloc] init];
    self.tabBarController.delegate = self;

    NSMutableArray *unsortedControllers = [NSMutableArray array];

    UIViewController *viewOne = [[UIViewController alloc] init];
    [unsortedControllers addObject:viewOne];

    UIViewController *viewTwo = [[UIViewController alloc] init];
    [unsortedControllers addObject:viewTwo];
    ...

在将它们全部实例化并添加到阵列后,您将通过查询NSUserDefaults来检查用户是否已自定义其订单。在默认值中,您将存储用户自定义标签栏顺序的数组。这将是一个NSNumbers数组(如何创建它在最后一个代码片段中解释)。使用这些来创建一个新的“排序”视图控制器数组,并将其传递给选项卡栏控制器。如果他们没有自定义订单,默认将返回nil,您可以简单地使用未排序的数组。

    ...
    NSArray *tabBarOrder = [[NSUserDefaults standardUserDefaults] arrayForKey:@"tabBarOrder"];
    if (tabBarOrder)
    {
      NSMutableArray *sortedControllers = [NSMutableArray array];
      for (NSNumber *sortNumber in tabBarOrder)
      {
         [sortedControllers addObject:[unsortedControllers objectAtIndex:[sortNumber intValue]]];
      }
      self.tabBarController.viewControllers = sortedControllers;
    } else {
      self.tabBarController.viewControllers = unsortedControllers;
    }
    [self.window setRootViewController:self.tabBarController];
    [self.window makeKeyAndVisible];

    return YES;
}

要创建自定义排序顺序,请使用UITabBarController的委托方法:

- (void)tabBarController:(UITabBarController *)tabBarController didEndCustomizingViewControllers:(NSArray *)viewControllers changed:(BOOL)changed
{
    NSMutableArray *tabOrderArray = [[NSMutableArray alloc] init];
    for (UIViewController *vc in self.tabBarController.viewControllers)
    {
        [tabOrderArray addObject:[NSNumber numberWithInt:[[vc tabBarItem] tag]]];
    }
    [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithArray:tabOrderArray] forKey:@"tabBarOrder"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

答案 4 :(得分:1)

根据Rickard&amp; amp;的答案,这就是我的诀窍。加斯帕。所有代码都进入主TabBarController。

import UIKit

class TabBarController: UITabBarController, UITabBarControllerDelegate {

let tabOrderKey = "customTabBarOrder"

override func viewDidLoad() {
    super.viewDidLoad()

    self.delegate = self
    loadCustomTabOrder()
}

func loadCustomTabOrder() {

    let defaults = NSUserDefaults.standardUserDefaults()
    let standardOrderChanged = defaults.boolForKey(tabOrderKey)

    if standardOrderChanged {
        print("Standard Order has changed")

        var VCArray = [UIViewController]()
        var tagNumber = 0

        let tabBar = self as UITabBarController

        if let countVC = tabBar.viewControllers?.count {
            print("\(countVC) VCs in total")
            for var x = 0; x < countVC; x++ {
                tagNumber = defaults.integerForKey("tabPosition\(x)")

                for VC in tabBar.viewControllers! {
                    if tagNumber == VC.tabBarItem.tag {
                        VCArray.append(VC)
                        print("Position \(x): \(VCArray[x].tabBarItem.title!) VC (tag \(tagNumber))")
                    }
                }
            }
        }
        tabBar.viewControllers = VCArray
    }

}

func tabBarController(tabBarController: UITabBarController, didEndCustomizingViewControllers viewControllers: [UIViewController], changed: Bool) {

    print("Change func called")

    if changed {
        print("Order has changed")
        let defaults = NSUserDefaults.standardUserDefaults()

        for var x = 0; x < viewControllers.count; x++ {
            defaults.setInteger(viewControllers[x].tabBarItem.tag, forKey: "tabPosition\(x)")
            print("\(viewControllers[x].tabBarItem.title!) VC (with tag: \(viewControllers[x].tabBarItem.tag)) is now in position \(x)")
        }
        defaults.setBool(true, forKey: tabOrderKey)
    } else {
        print("Nothing has changed")
    }
}

}

答案 5 :(得分:0)

简化的RickardElimää进一步回答。使用tabBarController CustomizingViewControllers的委托功能保存和加载Customized ViewControllers的“Swift”解决方案。

这就是我做到的。

class TabBarController: UITabBarController, UITabBarControllerDelegate {

    let kOrder = "customOrder"

    override func viewDidLoad() {
        super.viewDidLoad()
        self.delegate = self

        loadCustomizedViews()
    }

    func loadCustomizedViews(){
        let defaults = NSUserDefaults.standardUserDefaults()

        // returns 0 if not set, hence having the tabItem's tags starting at 1.
        let changed : Bool = defaults.boolForKey(kOrder)

        if changed {
            var customViewControllers = [UIViewController]()
            var tagNumber: Int = 0
            for (var i=0; i<self.viewControllers?.count; i++) {
                // the tags are between 0-6 and the
                // viewControllers in the array are between 0-6
                // so we swap them to match the custom order
                tagNumber = defaults.integerForKey( String(i) )

                //print("TabBar re arrange i = \(i), tagNumber = \(tagNumber),  viewControllers.count = \(self.viewControllers?.count) ")
                customViewControllers.append(self.viewControllers![tagNumber])
            }

            self.viewControllers = customViewControllers
        }
    }

    func tabBarController(tabBarController: UITabBarController, didEndCustomizingViewControllers viewControllers: [UIViewController], changed: Bool){

        if (changed) {
            let defaults = NSUserDefaults.standardUserDefaults()
            //print("New tab order:")
            for (var i=0; i<viewControllers.count; i++) {
                defaults.setInteger(viewControllers[i].tabBarItem.tag, forKey: String(i))
                //print("\(i): \(viewControllers[i].tabBarItem.title!) (\(viewControllers[i].tabBarItem.tag))")
            }

            defaults.setBool(changed, forKey: kOrder)
        }
    }
}

答案 6 :(得分:0)

更新了Swift 2.0的答案

`
    让tabBarOrderKey =“tabBarOrderKey”

DELIMITER ??
CREATE TRIGGER before_results_update
BEFORE UPDATE ON Student_Results
FOR EACH ROW BEGIN
INSERT INTO Result_Changes
SET ACTION = 'update',
ResultID = OLD.ID,
Result = OLD.Result,
User = USER(),
ChangedOn = NOW();
END ??
DELIMITER ;

}

`

请记住设置委托并在视图中加载

调用这些方法

答案 7 :(得分:0)

我想分享自己将近3天的代码,现在尝试各种错误和失败的组合-编码的一般寿命!哈哈。无论如何,下面的代码可用于Swift 5。 它是How to: Save order of tabs when customizing tabs in UITabBarController(Sam的代码)的提取,但具有Swift 5的for循环更新。 在TabBarViewController.swift文件中,一切工作正常。

因此,如果您只是将其粘贴到Swift文件中,请确保您的“标签栏”项具有Attributes Inspector中的标签号,并且您可以使用!

首先再次感谢Sam提供此守则。

import UIKit


class TabBarController: UITabBarController, UITabBarControllerDelegate {

let tabOrderKey = "customTabBarOrder"

override func viewDidLoad() {
super.viewDidLoad()

self.delegate = self
loadCustomTabOrder()
}

func loadCustomTabOrder() {

let defaults = UserDefaults.standard
let standardOrderChanged = defaults.bool(forKey: tabOrderKey)

if standardOrderChanged {
    print("Standard Order has changed")

    var VCArray = [UIViewController]()
    var tagNumber = 0

    let tabBar = self as UITabBarController

    if let countVC = tabBar.viewControllers?.count {
        print("\(countVC) VCs in total")
        for x in 0..<countVC {
            tagNumber = defaults.integer(forKey: "tabPosition\(x)")

            for VC in tabBar.viewControllers! {
                if tagNumber == VC.tabBarItem.tag {
                    VCArray.append(VC)
                    print("Position \(x): \(VCArray[x].tabBarItem.title!) VC (tag \(tagNumber))")
                }
            }
        }
    }
    tabBar.viewControllers = VCArray
 }

 }

func tabBarController(_ tabBarController: UITabBarController, didEndCustomizing viewControllers: [UIViewController], changed: Bool) {

print("Change func called")

if changed {
    print("Order has changed")
    let defaults = UserDefaults.standard

    for x in 0..<(viewControllers.count)  {
        defaults.set(viewControllers[x].tabBarItem.tag, forKey: "tabPosition\(x)")
        print("\(viewControllers[x].tabBarItem.title!) VC (with tag: \(viewControllers[x].tabBarItem.tag)) is now in position \(x)")
   }
    defaults.set(true, forKey: tabOrderKey)
    } else {
    print("Nothing has changed")
    }
  }

}