Cómo: Guardar el orden de las tabs al personalizar tabs en UITabBarController

Tengo problemas para encontrar cualquier otra información además de los documentos sobre cómo guardar el orden de tabulación para mi UITabBarController, de modo que la personalización del usuario se guarde para el siguiente lanzamiento de la aplicación. He buscado en línea, pero no he podido encontrar ninguna publicación de blog o artículo que tenga el código adecuado para hacer esto.

Me doy cuenta de que tengo que usar los métodos de delegado para UITabBarController (didEndCustomizingViewControllers 🙂 pero no estoy seguro de cómo acercarme mejor a la persistencia en términos de guardar el estado del orden en el que el usuario quiere las tabs.

¿Alguien puede publicar algún código, señalarme en la dirección correcta o quizás tenga un enlace para algo guardado? 🙂

Gracias

Por lo que ha pedido un código de muestra, simplemente publicaré aquí cómo me ocupé de la misma tarea en mi aplicación.

Introducción rápida: estaba usando un archivo NIB para almacenar el estado inicial de UITabBarController y para diferenciar mis tabs una de otra. Simplemente UITabBarItem variables de etiqueta para objetos UITabBarItem asignados a cada UIViewController relleno en mi UITabBarController . Para poder rastrear con precisión la última pestaña seleccionada (incluido el ‘Más’) he implementado los siguientes métodos para UITabBarControllerDelegate de mi UITabBarController y UINavigationControllerDelegate de moreNavigationController. Aquí están:

 #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"]; } 

Y aquí está el código para guardar el orden de las tabs:

 #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]; } 

Como puede ver, he almacenado el orden de los índices de las tabs en una matriz en NSUserDefaults .

En el lanzamiento de la applicationDidFinishLaunching: en applicationDidFinishLaunching: method UIViewControllers los UIViewControllers usando el siguiente código:

 - (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]; } 

Es bastante complicado y puede parecer extraño, pero no olvides que mi UITabBarController fue creado completamente en un archivo de punta. Si lo construye programáticamente, puede hacer lo mismo pero siguiendo el orden guardado.

PD: y no te olvides de sincronizar NSUserDefaults cuando finaliza tu aplicación.

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

Espero que esto sea de ayuda. Si algo no está claro, por favor comente y pregunte.

Primero voté la respuesta anterior, pero luego noté lo ridículamente compleja que es. Puede y debe ser simplificado.

 - (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]; } 

Todo esto sucede en AppDelegate. Establece el delegado de UITabBarController en la instancia de AppDelegate en Interface Builder. sharedSettingsService es lo que persiste en los datos para mí. Básicamente puede ser un front-end NSUserDefaults o cualquier cosa que desee (CoreData, por ejemplo). Así que todo es simple, Interface Builder ayuda aquí, no hace las cosas más complejas.

Tal vez tarde en el juego, pero he estado aprendiendo Swift durante menos de dos meses en la escuela y se sentó quizás más de quince horas con esto porque no pude encontrar una explicación decente en el interwebz.

Aquí hay una solución en Swift

  1. Asigne a todos los elementos de su tabItem una etiqueta, comenzando en 1. Haga esto en cada vista por separado. Si obtuvo seis vistas, sus tabItems tendrán en ese caso un número único, cada uno de los cuales oscilará entre 1 y 6.

  2. Agregue UITabBarControllerDelegate a todas las clases de ViewControllers para que pueda usar la función explicada más adelante en el punto 5.

     class FirstViewController: UIViewController, UITabBarControllerDelegate { 
  3. Agregue la siguiente variable globalmente (justo después del código anterior, como ejemplo) para que pueda guardar variables localmente en el teléfono desde cualquier función dentro de la clase.

     let defaults = NSUserDefaults.standardUserDefaults() 
  4. Delegue el tabBarController en la vista para que la vista pueda actualizar cualquier cambio en el tabBarController. Coloque lo siguiente en su viewDidLoad () .

     tabBarController!.delegate = self 
  5. Implementa el siguiente código Éste se activará cuando el usuario esté editando la vista de tabs. Lo que hace el código es tomar las tags [ViewControllers] en el orden en que se encuentran (después de que el usuario lo haya modificado) y guardarlas localmente en el teléfono. La primera etiqueta de viewController se guarda como un entero en la variable “0”, la segunda etiqueta en una variable llamada “1”, y así sucesivamente.

     func tabBarController(tabBarController: UITabBarController, didEndCustomizingViewControllers viewControllers: [UIViewController], changed: Bool) { if (changed) { print("New tab order:") for (var i=0; i 

Las impresiones le dicen el nuevo orden de las tabs. No necesitarás nada, pero creo que es bueno ver lo que sucede en el fondo. Todo esto fue solo para guardar el orden de las tabs. Ahora tendrá que recuperarlos cuando el progtwig esté comenzando.

  1. Cambie de su archivo UIViewControl a AppDelegate.swift .

  2. Finalmente, escriba lo siguiente en la aplicación func (aplicación: UIApplication, didFinishLaunchingWithOptions ... que puede encontrar en la parte superior de 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 

Lo que es bueno saber es que todas las vistas que contiene un tabBarController se almacenan como una matriz en tabBarController.viewControllers .

Este código básicamente crea una matriz llamada junkViewControllers . Luego, for-loop agrega los UIViewControllers existentes del progtwig en el orden de las variables almacenadas anteriores, según las tags de UIViewControllers. Cuando todo esto se hace, el tabBarController acortado a tabBar se sobrescribe con la matriz junkViewController .

Explicaré cómo hacer esto programáticamente. NOTA: Esto está usando ARC, por lo que es posible que tenga que insertar retener / liberar llamadas según sea necesario.

Utiliza la propiedad de tag de UITabBarItem para ordenar. Para cada UIViewController que está agregando al UITabBarController , asegúrese de que cada uno tenga una tag única.

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

Es de suponer que solo utilizaría su orden de clasificación predeterminado para sus tags, por lo que lo que tenga como su primer controlador de vista original sería 0, seguido de 1, 2, 3, etc.

Configure sus UIViewControllers en el archivo didFinishLaunchingWithOptions de AppDelegate como lo haría normalmente, asegurándose de que está creando instancias en su “orden predeterminada”. Al hacerlo, agréguelos a una instancia de 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]; ... 

Una vez que se hayan creado todas las instancias y se hayan agregado a la matriz, verificará si el usuario ha personalizado su orden consultando NSUserDefaults . En los valores predeterminados, almacenará una matriz del orden de barra de tabs personalizado del usuario. Esta será una matriz de NSNumbers (cómo se crea esto es explicar en el último fragmento de código). Úselos para crear una nueva matriz “ordenada” de controladores de visualización y pasarlos al controlador de la barra de tabs. Si no han personalizado el pedido, el valor predeterminado será nulo y usted simplemente puede usar el conjunto no ordenado.

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

Para crear un orden de clasificación personalizado, use el método delegado 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]; } 

Esto es lo que hizo el truco para mí, basándose en las respuestas de Rickard y Jesper. Todo el código va al TabBarController principal.

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

Simplificado Rickard Elimää responde aún más. Solución “Swift” para guardar y cargar ViewControllers personalizados utilizando la función de delegado de tabBarController CustomizingViewControllers.

Así es como lo hice.

 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 

Respuesta actualizada para 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) } } } 

}

`

Recuerde configurar el delegado y llamar a estos métodos en la vista cargada