UINavigationItem 動(dòng)畫(huà)
UINavigationItem
左右兩邊都能設(shè)置 UIBarButtonItem
,由于 UIBarButtonItem
不是 UIView
子類,所以無(wú)法直接對(duì)其進(jìn)行動(dòng)畫(huà)。UIBarButtonItem
有個(gè) customView
屬性,可以利用這個(gè)來(lái)動(dòng)畫(huà),但是定義了這個(gè)屬性后,UIBarButtonItem原本的 target-action 模式將失效,為了使其能夠繼續(xù)響應(yīng)觸摸事件,最好使用 UIButton,即能響應(yīng)觸摸事件,也能對(duì)其動(dòng)畫(huà)。
實(shí)際中,這么做還是有很多麻煩的。如果要保持 UIBarButtonItem 的外觀和風(fēng)格與原來(lái)一致,得需要還原度很高的圖片素材:尺寸保持一致,能夠響應(yīng) tintColor。很難找到這樣的素材,對(duì)于不會(huì)畫(huà)畫(huà)的我而言,無(wú)解。比如對(duì)于 + 這個(gè)符號(hào)的 UIBarButtonItem
,找不到對(duì)應(yīng)的素材,在 UIButton
中利用 titleLabel
來(lái)設(shè)置,字體風(fēng)格不搭。
titleView 動(dòng)畫(huà)
上圖是一個(gè)對(duì) titleView 進(jìn)行縮放顯示的動(dòng)畫(huà)。一般的思路是直接對(duì) titleView 進(jìn)行動(dòng)畫(huà)。
self.navigationItem.titleView = self.segmentedControl;
self.navigationItem.titleView.transform = CGAffineTransformMakeScale(0.1, 0.1);
[UIView animateWithDuration:0.5
delay:0
usingSpringWithDamping:1
initialSpringVelocity:1
options:UIViewAnimationOptionShowHideTransitionViews
animations:^{
self.navigationItem.titleView.transform = CGAffineTransformMakeScale(1, 1);
}
completion:^(BOOL finished){
[self.collectionView reloadData];
}];
這時(shí)候還沒(méi)有問(wèn)題,但是想要 titleView以同樣的風(fēng)格消失時(shí),直接對(duì) titleView 進(jìn)行縮放動(dòng)畫(huà)的結(jié)果是縮放后比例不對(duì),而且 titleView 的位置也移動(dòng)了,甚至是相對(duì)于與leftBarButtonItem 的距離按照動(dòng)畫(huà)中指定的Y 軸比例進(jìn)行移動(dòng)的。在 stackoverflow 上有人也遇到類似問(wèn)題,由于不清楚內(nèi)部的實(shí)現(xiàn),為了規(guī)避這個(gè)問(wèn)題,方法就是將要?jiǎng)赢?huà)的視圖封裝進(jìn)一個(gè) UIView 再賦值給 titleView,并只在該視圖上進(jìn)行動(dòng)畫(huà),而不是在 titleView 上進(jìn)行動(dòng)畫(huà)。
先封裝:
UIView *backView = [[UIView alloc] initWithFrame:self.segmentedControl.bounds];
[backView addSubview:self.segmentedControl];
self.navigationItem.titleView = backView;
/*縮放動(dòng)畫(huà)*/
在segmentedControl 上進(jìn)行動(dòng)畫(huà),不能在 backView 或是 titleView 上動(dòng)畫(huà)。猜測(cè)是對(duì)視圖的 frame 做更改時(shí)而沒(méi)有調(diào)整子視圖的布局造成的,有誰(shuí)能去回答一下?
UIView *backView = self.navigationItem.titleView;
UIView *segmentedControl = backView.subviews.firstObject;
[UIView animateWithDuration:0.3
delay:0
usingSpringWithDamping:1
initialSpringVelocity:1
options:UIViewAnimationOptionLayoutSubviews
animations:^{
segmentedControl.transform = CGAffineTransformMakeScale(0.1, 0.1);
}
completion:^(BOOL finished){
self.navigationItem.titleView = nil;
self.segmentedControl.transform = CGAffineTransformMakeScale(1, 1);
self.navigationItem.title = self.assetCollection.localizedTitle;
}];
PHPhotos 更新與視圖更新
對(duì)相冊(cè)進(jìn)行操作,添加或刪除照片時(shí),通過(guò)PHPhotoLibrary 的
- (void)performChanges:(dispatch_block_t)changeBlock completionHandler:(void (^)(BOOL success, NSError *error))completionHandler
方法來(lái)提出請(qǐng)求。真正執(zhí)行數(shù)據(jù)更新是在
- (void)photoLibraryDidChange:(PHChange *)changeInstance
這要求注冊(cè)為 PHPhotoLibrary 的觀察者:
[[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];
在請(qǐng)求的方法中,completionHandler的名字誤導(dǎo)讓我以為其會(huì)在- (void)photoLibraryDidChange:(PHChange *)changeInstance
執(zhí)行完畢后調(diào)用,實(shí)際上它是在changeBlock 結(jié)束后在執(zhí)行 changeBlock 的串行隊(duì)列中調(diào)用。因此還是在- (void)photoLibraryDidChange:(PHChange *)changeInstance
中更新數(shù)據(jù)的同時(shí)更新 UI 吧。好吧,這是我文檔沒(méi)看仔細(xì)。
磁盤(pán)文件讀取(這是個(gè)老坑了)
如果你希望將圖像保存在應(yīng)用的 Documents 或 Library 目錄下,并且希望在下次啟動(dòng)后使用[UIImage imageWithContentsOfFile:]
從磁盤(pán)中獲取圖像時(shí),不要試圖保存圖像文件的絕對(duì)路徑。每次應(yīng)用的升級(jí)會(huì)造成這個(gè)絕對(duì)路徑發(fā)生變化(多謝 @千飛若逸Fee 關(guān)于這條的補(bǔ)充),而且從 iOS 8 開(kāi)始這兩個(gè)目錄的不再與你的應(yīng)用 Bundle 綁定,這兩個(gè)目錄的路徑值都是動(dòng)態(tài)的,每次應(yīng)用啟動(dòng)都會(huì)是不一樣的結(jié)果,見(jiàn)官方文檔或見(jiàn)我的提問(wèn)。正確方法是,只保留文件在這兩個(gè)目錄下的相對(duì)路徑,使用NSFileManager
的- URLsForDirectory:inDomains:
方法來(lái)獲取這兩個(gè)目錄的路徑,再拼成絕對(duì)路徑來(lái)訪問(wèn)。