Как: сохранить порядок вкладок при настройке вкладок в UITabBarController - PullRequest
11 голосов
/ 09 января 2010

У меня проблемы с поиском любой другой информации, кроме документации о том, как сохранить порядок вкладок для моего UITabBarController, чтобы настройки пользователя были сохранены для следующего запуска приложения. Я выполнил поиск в Интернете, но не смог найти ни одного сообщения в блоге или статей, в которых указан соответствующий код для этого.

Я понимаю, что должен использовать методы делегата для UITabBarController (didEndCustomizingViewControllers :), но я не уверен, как лучше подходить к стойкости с точки зрения сохранения состояния порядка, в котором пользователь хочет вкладки.

Может кто-нибудь опубликовать какой-нибудь код, указать мне верное направление или, возможно, у вас есть ссылка на что-то сохраненное? :)

Спасибо

Ответы [ 7 ]

18 голосов
/ 09 января 2010

Насколько вы просили некоторый пример кода, я просто опубликую здесь, как я справился с той же задачей в моем приложении.

Краткое вступление: я использовал NIB-файл для хранения начального состояния UITabBarController и для того, чтобы отличать свои вкладки друг от друга, я просто определил переменные тега для UITabBarItem объектов, назначенных каждому UIViewController, вставленному в мой UITabBarController. Чтобы иметь возможность точно отслеживать последнюю выбранную вкладку (включая «Больше»), я реализовал следующие методы для UITabBarControllerDelegate моего UITabBarController и UINavigationControllerDelegate его moreNavigationController. Вот они:

#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 был полностью создан в файле пера. Если вы создаете это программно, вы можете просто сделать то же самое, но следуя сохраненному порядку.

P.S .: и не забудьте синхронизировать NSUserDefaults при завершении работы приложения.

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

Надеюсь, это поможет. Если что-то не понятно, пожалуйста, прокомментируйте и спросите.

15 голосов
/ 25 января 2010

Сначала я проголосовал за предыдущий ответ, но потом заметил, насколько это нелепо сложно. Это можно и нужно упростить.

- (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. Вы устанавливаете делегат UITabBarController на экземпляр AppDelegate в Интерфейсном Разработчике. sharedSettingsService - это то, что сохраняет данные для меня. По сути, это может быть интерфейс NSUserDefaults или все что угодно (например, CoreData). Так что все просто, Интерфейсный Разработчик помогает здесь, а не делает вещи более сложными.

3 голосов
/ 05 ноября 2015

Возможно, опоздал к игре, но изучал Swift менее двух месяцев в школе и сидел, возможно, более пятнадцати часов с этим, потому что я не смог найти достойного объяснения на интервеже.

Вот решение в Swift

  1. Дайте всем вашим tabItem тег, начиная с 1. Вы делаете это в каждом отдельном представлении. Если у вас есть шесть представлений, в этом случае их tabItems будет иметь уникальный номер в диапазоне от 1 до 6.

  2. Добавьте UITabBarControllerDelegate ко всем классам ViewControllers, чтобы вы могли использовать функцию, описанную ниже в пункте 5.

    class FirstViewController: UIViewController, UITabBarControllerDelegate {
    
  3. Добавьте следующую глобальную переменную (например, сразу после кода выше), чтобы вы могли локально сохранять переменные на телефоне из любой функции в классе.

    let defaults = NSUserDefaults.standardUserDefaults()
    
  4. Делегируйте tabBarController для представления, чтобы представление могло обновить любые изменения в tabBarController. Поместите следующее в viewDidLoad () .

    tabBarController!.delegate = self
    
  5. Реализуйте следующий код. Этот активируется, когда пользователь редактирует вид вкладки. Код использует теги [ViewControllers] в том порядке, в котором они находятся (после того, как пользователь их изменил), и сохраняет их локально на телефоне. Первый тег viewController сохраняется как целое число в переменной «0», второй тег - в переменной «1» и т. Д.

    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))")
            }
        }
    }
    

Отпечатки сообщают вам новый порядок вкладок. Ничего вам не понадобится, но я думаю, приятно видеть, что происходит на заднем плане. Все это было только для того, чтобы сохранить порядок вкладок. Теперь вам нужно будет получить их при запуске программы.

  1. Переключение из вашего файла UIViewControl в AppDelegate.swift .

  2. Наконец, напишите следующее в func application (application: UIApplication, didFinishLaunchingWithOptions ..., которое вы можете найти в верхней части AppDelegate.swift .

    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
    }
    }
    

Хорошо знать, что все представления, которые содержит tabBarController, хранятся в виде массива в tabBarController.viewControllers .

Этот код в основном создает массив с именем junkViewControllers . Затем цикл for добавляет существующие UIViewControllers из программы в порядке предыдущих сохраненных переменных на основе тегов UIViewControllers. Когда все это сделано, tabBarController, сокращенный до tabBar , перезаписывается массивом junkViewController .

1 голос
/ 18 марта 2016

Это то, что помогло мне, основываясь на ответах Рикарда и Джеспера. Весь код переходит в основной 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")
    }
}

}
1 голос
/ 06 декабря 2011

Я объясню, как это сделать программно. ПРИМЕЧАНИЕ. При этом используется ARC, поэтому при необходимости может потребоваться вставить вызовы удержания / разблокировки.

Вы используете tag свойство 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 и т. Д.

Установите свои контроллеры UIViewControllers в didFinishLaunchingWithOptions AppDelegate, как вы это обычно делаете, убедившись, что вы создаете их экземпляры в «порядке по умолчанию». При этом добавьте их в экземпляр 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 (как это создается, объясняется в последнем фрагменте кода). Используйте их для создания нового «отсортированного» массива контроллеров представления и передачи его контроллеру панели вкладок. Если они не изменили порядок, по умолчанию вернется ноль, и вы можете просто использовать несортированный массив.

    ...
    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];
}
0 голосов
/ 03 августа 2016

Обновлен ответ на Swift 2.0

`
let tabBarOrderKey = "tabBarOrderKey"

extension TabBarButtonsController: UITabBarControllerDelegate {

 // Saves new tab bar custom order

  func tabBarController(tabBarController: UITabBarController, didEndCustomizingViewControllers viewControllers: [UIViewController], changed: Bool) {
var orderedTagItems = [Int]()
if changed {
  for viewController in viewControllers {
    let tag = viewController.tabBarItem.tag
    orderedTagItems.append(tag)

  }
  NSUserDefaults.standardUserDefaults().setObject(orderedTagItems, forKey: tabBarOrderKey)
}
}

// set up tag to compare with when pulling from defaults and for saving initial tab bar change

func setUpTabBarItemTags() {
var tag = 0
if let viewControllers = viewControllers {
  for view in viewControllers {
    view.tabBarItem.tag = tag
    tag += 1
  }
 }
}

// Get Saved Tab Bar Order from defaults

func getSavedTabBarItemsOrder() {
var newViewControllerOrder = [UIViewController]()
if let initialViewControllers = viewControllers {
  if let tabBarOrder = NSUserDefaults.standardUserDefaults().objectForKey(tabBarOrderKey) as? [Int] {
    for tag in tabBarOrder {
      newViewControllerOrder.append(initialViewControllers[tag])
    }
    setViewControllers(newViewControllerOrder, animated: false)
  }
 }
}

}

`

Не забудьте установить делегат и вызвать эти методы в представлении загрузил

0 голосов
/ 15 января 2016

Упрощенный Рикард Элимяа ответит еще дальше. «Быстрое» решение для сохранения и загрузки пользовательских ViewControllers с использованием функции делегата tabBarController CustomizingViewControllers.

Вот как я это сделал.

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)
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...