Практическое руководство. Сохранение порядка вкладок при настройке вкладок в UITabBarController
У меня возникают проблемы с поиском какой-либо другой информации, кроме документов, как сохранить порядок вкладок для моего UITabBarController, чтобы пользовательская настройка была сохранена для следующего запуска приложения. Я искал в Интернете, но не смог найти никаких сообщений в блоге или статей, которые проходят через соответствующий код для этого.
Я понимаю, что мне нужно использовать методы делегата для UITabBarController (didEndCustomizingViewControllers:), но я не уверен, как наилучшим образом подойти к сохранению состояния заказа, в котором пользователь хочет видеть вкладки.
Может кто-нибудь отправить какой-то код, указать мне в правильном направлении или, возможно, у вас есть ссылка на что-то сохраненное?:)
Спасибо
Ответы
Ответ 1
Насколько вы просили какой-то образец кода, я просто отправлю здесь, как я имел дело с одной и той же задачей в своем приложении.
Быстрое введение: я использовал файл 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
был полностью создан в файле nib. Если вы его программно создаете, вы можете просто сделать то же самое, но следовать сохраненному порядку.
P.S.: и не забудьте синхронизировать NSUserDefaults
, когда ваше приложение завершается.
- (void)applicationWillTerminate:(UIApplication *)application {
[[NSUserDefaults standardUserDefaults] synchronize];
}
Надеюсь, это поможет. Если что-то неясно, прокомментируйте и спросите.
Ответ 2
Сначала я проголосовал за предыдущий ответ, но потом я заметил, насколько это смехотворно сложно. Он может и должен быть упрощен.
- (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 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 в Interface Builder. sharedSettingsService - это то, что сохраняет данные для меня. В основном это может быть интерфейс NSUserDefaults или все, что вам нравится (например, CoreData). Итак, все просто, Interface Builder помогает здесь, а не делает вещи более сложными.
Ответ 3
Возможно, поздно в игре, но изучал Свифта менее двух месяцев в школе и сидел, возможно, более пятнадцати часов с этим, потому что я не мог найти достойного объяснения в interwebz.
Вот решение в Swift
-
Дайте все ваши теги tabItem, начиная с 1. Вы делаете это в каждом отдельном представлении. Если у вас есть шесть просмотров, их вкладки будут иметь в этом случае уникальный номер в диапазоне от 1 до 6.
-
Добавьте UITabBarControllerDelegate ко всем классам ViewControllers, чтобы вы могли использовать функцию, описанную ниже в пункте 5.
class FirstViewController: UIViewController, UITabBarControllerDelegate {
-
Добавьте следующую переменную глобально (сразу после кода выше, в качестве примера), чтобы вы могли сохранять переменные локально на телефоне из любой функции внутри класса.
let defaults = NSUserDefaults.standardUserDefaults()
-
Делегируйте tabBarController в представление, чтобы представление могло обновлять любые изменения в tabBarController. Поместите следующее в свой viewDidLoad().
tabBarController!.delegate = self
-
Внедрите следующий код. Этот режим активируется, когда пользователь редактирует представление вкладки. Что делает код, он принимает теги [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))")
}
}
}
Отпечатки скажут вам новый порядок вкладок. Ничего вам не понадобится, но я думаю, что приятно видеть, что происходит в фоновом режиме. Все это было только для сохранения порядка вкладок. Теперь вам нужно будет восстановить их при запуске программы.
-
Переключитесь с вашего файла UIViewControl на AppDelegate.swift.
-
Наконец, напишите следующее в приложении func (приложение: 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 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-loop добавляет существующие UIViewControllers из программы в порядке от предыдущих сохраненных переменных на основе тегов UIViewControllers. Когда все это будет сделано, tabBarController, сокращенный до tabBar, будет перезаписан массивом junkViewController.
Ответ 4
Я объясню, как это сделать программно. ПРИМЕЧАНИЕ. Это использование 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 в AppDelegate didFinishLaunchingWithOptions
, как обычно, убедитесь, что вы создаете их в своем "порядке по умолчанию". По мере этого добавьте их в экземпляр 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];
}
Ответ 5
Вот что помогло, основываясь на ответах Рикарда и Йеспера. Весь код входит в основной 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")
}
}
}
Ответ 6
Упрощенный Рикард Элимяэ ответит еще дальше. "Быстрое" решение для сохранения и загрузки настраиваемых 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 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)
}
}
}
Ответ 7
Обновлен ответ для 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)
}
}
}
}
`
Не забудьте установить делегат и вызвать эти методы в представлении, загрузив