Settings Bundle是在自己的程序中建立的一組文件,利用它可以告訴設備中的Settings程序我們寫的程序有哪些設置項。用戶在Settings程序中設置好相關相關選項後回到我們自己的程序,自己的程序中的對應項也會發生相應的變化。
在iOS程序中,用戶默認項,即上面所說的設置項,是用NSUserDefaults類實現的。在NSUserDefaults類中使用關鍵字來讀取和存儲設置項的具體數據,就像NSDictionary類一樣,不同的是,NSUserDefaults類的數據是存儲在文件系統中的,而不是作爲一個對象實例放在內存中。
在這篇文章中,我們將創建一個程序,爲它添加和配置Settings Bundle,之後可以在Settings程序中顯示和配置相關選項。在Settings Bundle中使用plist文件來定義程序中允許的設置項,Settings程序會自動建立接口。Settings Bundle中的plist文件必須遵循特定的格式,不過Xcode會幫助我們遵循這種格式。
1、首先下載初始代碼。http://www.oschina.net/code/snippet_164134_10458
由於我們的重點是Settings Bundle的使用,那麼建立工程、實現頁面跳轉等等就不詳細說明了。
2、解壓Settings Bundle Test.zip,使用Xcode 4.3打開此工程,先打開FirstViewController.xib,使用IB向其中添加控件,如下圖:
然後爲這些標籤向FirstViewController.h中建立Outlet映射:
3、打開MoreViewController.xib,向其中添加控件,如下:
然後,向MoreViewController.h中,爲右邊的兩個Label以及UISlider與UISWitch控件創建Outlet映射,爲UISlider與UISWitch控件添加Action映射:
然後在Attribute Insepector中設置UISlider控件最小值、最大值和默認值分別是0、10和5:
將準備好的兩張圖片添加到工程中,在Attribute Insepector中設置UISlider控件的Min Image與Max Image:
4、接下來,爲程序建立Settings Bundle。依次選擇File — New — File…,找到Settings Bundle:
單擊Next,設置好名稱和分組:
然後單擊Create,則創建了Settings.bundle。
5、展開Settings.bundle,其中包含一個Root.plist。Settings程序中的顯示項就是從Root.plist中獲取的。
單擊Root.plist以打開它,在空白處單擊,選中Show Raw Keys/Values:
接下來,我們展開PreferenceSpecifiers那一項,刪除除了Group之外的其他項。
PreferenceSpecifiers這個對應於剛打開Settings程序時第一頁中該應用程序的一個標籤,如果此時運行程序,然後在模擬器返回桌面,再打開Settings程序,則其中會出現Settings Bundle Test這一項:
上圖中的Settings Bundle Test這一項就可以理解爲是從PreferenceSpecifiers獲取的。
6、展開PreferenceSpecifiers這一項,先向其中添加三行,每一行的設置如下:
此時運行程序,在Settings程序中單擊上圖中的Settings Bundle Test那一項,出現的頁面如下圖:
在Root.plist文件中,Item 0那一項的類型是PSGroupSpecifier,它表示一個分組,則它下面的每Item 1到Item 3都是在這一組,直到下一個PSGroupSpecifier出現。
Item 1與Item 2都是PSTextFieldSpecifier類型的,它們都是文本框,可以通過爲其添加子項限制這些文本框的輸入。
Item 3是一個多選框,可供選擇的值是由Titles與Values決定的,Titles與Values這兩項內容是一樣的,但是缺一不可。
7、之後,再向其中添加Item 4到Item 7,如下圖:
再運行程序,打開Settings程序看看:
8、之後,我們實現在上面左圖的下方出現一項“更多設置”,單擊此項跳轉到新的頁面。先創建一個plist文件,名稱爲MoreSettings.plist,創建方法就不說了吧,參考http://my.oschina.net/plumsoft/blog/42084第二步。注意現在只是創建到工程中而不是Settings.bundle中,想要加到Settings.bundle中還要其他操作,稍後詳解。
右擊Settings.bundle,選擇Show in Finder:
然後在Finder中右擊Settings.bundle,選擇“顯示包含內容”:
在打開的地方將MoreSettings.plist以及上面用到的兩張圖片拷貝進去。
9、編輯Settings.bundle中的MoreSettings.plist內容如下:
保存後,在Root.plist添加一行:
注意,Item 8的類型是通過選擇其子選項Type的類型改變的。
此時運行程序,Settings程序如下:
10、接下來都是代碼了。
10.1 在ViewController.h中添加代碼:
#define kUserName @"username" #define kPassWord @"password" #define kGender @"gender" #define kFavouriteColor @"favouritecolor" #define kFavouriteSeason @"favouriteseason" #define kFavouriteSport @"favouritesport" #define kTheSlider @"theslider" #define kTheSwitch @"theswitch"
10.2 在FirstViewController.h與MoreViewController.h中分別聲明一個方法,名爲
- (void)refreshFields;
在FirstViewController.m中添加代碼如下:
- (void)refreshFields { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; self.userNameLabel.text = [defaults objectForKey:kUserName]; self.passWordLabel.text = [defaults objectForKey:kPassWord]; self.genderLabel.text = [defaults objectForKey:kGender]; self.colorLabel.text = [defaults objectForKey:kFavouriteColor]; self.seasonLabel.text = [defaults objectForKey:kFavouriteSeason]; self.sportLabel.text = [defaults objectForKey:kFavouriteSport]; }
在MoreViewController.m中添加代碼如下:
- (void)refreshFields { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; self.theSwitch.on = [defaults boolForKey:kTheSwitch]; self.slider.value = [defaults floatForKey:kTheSlider]; self.sliderValueLabel.text = [[defaults objectForKey:kTheSlider]stringValue]; }
10.3 實現MoreViewController.m中的sliderTapped與switchTapped方法如下:
- (IBAction)sliderTapped:(id)sender { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setFloat:self.slider.value forKey:kTheSlider]; self.sliderValueLabel.text = [[defaults objectForKey:kTheSlider] stringValue]; [defaults synchronize]; } - (IBAction)switchTapped:(id)sender { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setBool:self.theSwitch.on forKey:kTheSwitch]; [defaults synchronize]; }
10.4 在FirstViewController.m與MoreViewController.m中@end之前都添加代碼:
- (void)applicationWillEnterForeground:(NSNotification *)notification { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults synchronize]; [self refreshFields]; }
10.5 在FirstViewController.m與MoreViewController.m的viewDidLoad方法中都添加代碼:
[self refreshFields]; UIApplication *app = [UIApplication sharedApplication]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:app];
10.6 在FirstViewController.m與MoreViewController.m中的ViewDidUnload方法中都添加代碼:
[[NSNotificationCenter defaultCenter] removeObserver:self];
11.7 在ViewController.m的viewDidLoad方法中的[super viewDidLoad];之前添加代碼:
//註冊默認項 NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], kTheSwitch, [NSNumber numberWithFloat:5.0], kTheSlider, nil]; [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
11、運行,那麼Settings Bundle Test程序中的數據將會隨着Settings程序中的選項改變而改變,反過來也是。
例如,在Settings程序中設置如下:
返回Settings Bundle Test程序,顯示如下:
不過,第一次運行程序時,單擊“更多設置”按鈕,Slider與Switch是變形的,然後纔會顯示正確的值:
真是好事多磨啊。
剛運行程序,第一次單擊“更多設置”按鈕就會出現上圖情況。猜想是因爲剛開始ViewController中的moreViewController爲空,在頁面跳轉時才創建它。爲此,試試在ViewController.m的viewDidLoad方法的最後一條語句之前添加代碼:
self.moreViewController = [[MoreViewController alloc] initWithNibName:@"MoreViewController" bundle:nil]; self.moreViewController.viewController = self;
再運行試試,還是不行。那估計是跟頁面跳轉時的動態效果有關了。再把ViewController.m的switchViews方法修改如下:
- (void)switchViews { if (self.moreViewController.view.superview == nil) { if (self.moreViewController == nil) { self.moreViewController = [[MoreViewController alloc] initWithNibName:@"MoreViewController" bundle:nil]; self.moreViewController.viewController = self; } } else { if (self.firstViewController == nil) { self.firstViewController = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil]; self.firstViewController.viewController = self; } } [UIView beginAnimations:@"View Flip" context:nil]; [UIView setAnimationDuration:0.80]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; if (self.moreViewController.view.superview == nil) { [UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES]; [self.firstViewController.view removeFromSuperview]; [self.view insertSubview:self.moreViewController.view atIndex:0]; } else { [UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES]; [self.moreViewController.view removeFromSuperview]; [self.view insertSubview:self.firstViewController.view atIndex:0]; } [UIView commitAnimations]; }
再運行,問題總算解決了。
最終代碼:http://www.oschina.net/code/snippet_164134_10484
以下是原作者與提問者的交互,很有幫助,一起粘來供大家學習: