一些小的功能點,雖然很小,但是里面有些彎,值得注意。(同系列文章會持續(xù)更新.......)
1.tableHeaderView的使用:
這個效果的實現(xiàn)有種比較巧妙的地方:
self.HeadImgView= [[UIImageViewalloc]initWithFrame:CGRectMake(0,0,Width,HeadImgHeight)];
self.HeadImgView.image= [UIImageimageNamed:@"eee"];
[self.tableView ?addSubview:self.HeadImgView];
//與圖像高度一樣防止數(shù)據(jù)被遮擋
self.tableView.tableHeaderView= [[UIViewalloc]initWithFrame:CGRectMake(0,0,Width,HeadImgHeight)];
? 然后在scrollViewDidScroll 的代理方法中根據(jù) sc 的偏移來動態(tài)的改變? self.HeadImgView 的 frame就可以達到這樣的效果了。
但是,這里有個彎,如果不是把這個試圖?addSubview? 在tableView 上的話,直接
self.tableView.tableHeaderView= self.HeadImgView
的話,在代理中再改變? self.HeadImgView的 frame ?就會出現(xiàn)下拉時上面出現(xiàn)空白的情況。
2.在導(dǎo)航條上放視圖,點擊字體變大:
往導(dǎo)航條上加試圖的關(guān)鍵點:
? ?self.navigationItem.titleView= view;(這個view 是 UIScrollView)也就是上面的標題區(qū)域
放縮關(guān)鍵點:
bgview.transform=CGAffineTransformScale(CGAffineTransformIdentity,0.85,0.85);
或者 ? ? ? ? ? ?bgview.transform=CGAffineTransformMakeScale(0.85, 0.85);
3.上滑顯示和隱藏導(dǎo)航條:
? ? ? NavigationBar他背后是有一張類型為_UINavigationBarBackground(UIImageView的子類)的視圖,我們平時看到的大部分其實都是它,第二個箭頭那里的ImageView就是那根細線,他是加在我們背景的ImageView上面的,我們設(shè)置BackgroundImage其實就是設(shè)置_UINavigationBarBackground的image。
? ? 設(shè)置導(dǎo)航條變透明:
? ? ? ?[self.navigationController.navigationBar setBackgroundImage:[UIImage new] ??forBarMetrics:UIBarMetricsDefault];
設(shè)置導(dǎo)航條下的那條線隱藏起來:(這三條都實現(xiàn)才行)
方法一:
? ? ? ? [self.navigationController.navigationBar setBackgroundImage:[UIImage new]forBarMetrics:UIBarMetricsDefault];//這樣帶來的壞處是導(dǎo)航條會占位64像素
self.navigationController.navigationBar.shadowImage= [UIImage new];
self.navigationController.navigationBar.translucent=NO;
方法二:
//遞歸查找出那條線
navBarHairlineImageView = [[MethodTool shareTool] findHairlineImageViewUnder:self.navigationController.navigationBar];
//隱藏
navBarHairlineImageView.hidden = YES;
實現(xiàn)這個效果的關(guān)鍵點:
barImageView=self.navigationController.navigationBar.subviews.firstObject;//用一個全局的指針,指向那個 imageView,根據(jù)表的y值上的偏移量,要動態(tài)的改變 ?這個imageview的 透明度即可,。
- (void)scrollViewDidScroll:(UIScrollView*)scrollView
{
NSLog(@"YYYY:%f",scrollView.contentOffset.y);
CGFloatoffset = scrollView.contentOffset.y;
CGFloatalpha = (offset/100);
barImageView.alpha= alpha;
}
PS:其實可以用一個自定義的導(dǎo)航條,根據(jù)表的偏移量要動態(tài)的改變自定義試圖的透明度。。
4.隱藏導(dǎo)航條下的細線(兩種方法):
(1)
[self.navigationController.navigationBarsetBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage= [UIImage new];
self.navigationController.navigationBar.translucent=NO;
這種方式有個副作用就是他回使導(dǎo)航條占64個像素,如果是整個項目都做完之后使用這種方法隱藏的話需要修改全局 試圖的 ?Y坐標起始點是 0 而不是原來的64 ,所以建議 設(shè)置一個全局的宏定義 NAVHEIGHT 導(dǎo)航條的高度,來隨時更改,更可控更方便
(2)
? ? UIImageView ? *navBarHairlineImageView;//一個全局的指針
navBarHairlineImageView= [selffindHairlineImageViewUnder:self.navigationController.navigationBar];
navBarHairlineImageView.hidden=YES;
//使用了一個遞歸調(diào)用找到那個1像素高度的線,并隱藏它
- (UIImageView*)findHairlineImageViewUnder:(UIView*)view {
if([view isKindOfClass:UIImageView.class] && view.bounds.size.height<=1.0) {
return(UIImageView*)view;
}
for(UIView*subview in view.subviews) {
UIImageView*imageView = [self findHairlineImageViewUnder:subview];
if(imageView) {
returnimageView;
}}returnnil;
}
5.點擊旋轉(zhuǎn)全屏顯示:
- (void)frameChange:(UIButton*)sender {
NSIntegeri = sender.tag;
if(!sender.selected) {
sender.selected=YES;
origanRect=viewPlay[i].frame;
origanSuperV=viewPlay[i].superview;
[UIViewbeginAnimations:nilcontext:nil];
[UIViewsetAnimationDuration:0.3];
viewPlay[i].transform=CGAffineTransformMakeRotation(M_PI*(90)/180.0);
viewPlay[i].bounds=CGRectMake(0,0,HEIGHT,WIDTH);
viewPlay[i].center=CGPointMake(WIDTH/2,HEIGHT/2);
[[UIApplicationsharedApplication].keyWindowaddSubview:viewPlay[i]];
[UIViewcommitAnimations];
sender.frame=CGRectMake(0,0,CGRectGetHeight(viewPlay[i].frame),CGRectGetWidth(viewPlay[i].frame));
}else{
sender.selected=NO;
[UIViewbeginAnimations:nilcontext:nil];
[UIViewsetAnimationDuration:0.3];
viewPlay[i].transform=CGAffineTransformMakeRotation(0);
viewPlay[i].frame=origanRect;
[origanSuperVaddSubview:viewPlay[i]];
[UIViewcommitAnimations];
sender.frame=CGRectMake(0,0,CGRectGetWidth(viewPlay[i].frame),CGRectGetHeight(viewPlay[i].frame));
}
}
UIView*viewPlay[PAGECOUNT*PAGEVIEWCOUNT]; ?聲明一個數(shù)組行的UIview 組。
viewPlay[i].center的設(shè)置很重要,不管是使用? viewPlay[i].bounds? 還是?viewPlay[i].frame?都需要設(shè)置,是因為 系統(tǒng)自帶的旋轉(zhuǎn)是按照一段弧形的軌跡而不是中心點旋轉(zhuǎn),如果不設(shè)置
個人更推薦第二個
6.使用 UICollectionView? 來展示圖片多選:
圖片多選擇中使用 UICollectionView ?來展示圖片,好處:展示簡單,刪除更簡單。
實現(xiàn)關(guān)鍵點:
-(UICollectionViewCell*)collectionView:(UICollectionView*)collectionView ? ? ? ? ? ? ?cellForItemAtIndexPath:(NSIndexPath*)indexPath{
?**最后一個item**
?if(indexPath.item==arrayImages.count) {
? ?CleandarCollectionViewCell*cell = ? ? ?[collectionViewdequeueReusableCellWithReuseIdentifier:@"CleandarCollectionViewCell"fo rIndexPath:indexPath];
cell.imgV.image= [UIImageimageNamed:@"add_photo"];
cell.backgroundColor= [UIColorgrayColor];
returncell;
}
**其他item**
CleandarCollectionViewCell*cell = ? [collectionViewdequeueReusableCellWithReuseIdentifier:@"CleandarCollectionViewCell"forIndexPath:indexPath];
[cell.imgVsetImage:arrayImages[indexPath.item]];
returncell;
}
-(void)collectionView:(UICollectionView*)collectionView didSelectItemAtIndexPath:(NSIndexPath*)indexPath{
[self.viewendEditing:YES];
**最后一個**
if(indexPath.item==arrayImages.count) {
UIActionSheet*sheet = [[UIActionSheetalloc]initWithTitle:@"相片來源"delegate:selfcancelButtonTitle:@"取消"destructiveButtonTitle:nilotherButtonTitles:@"相機",@"相冊",nil];
[sheetshowInView:self.view];
}else{
UIAlertController*alertController = [UIAlertControlleralertControllerWithTitle:@"確定刪除該張圖片"message:nilpreferredStyle:UIAlertControllerStyleAlert];
UIAlertAction*action = [UIAlertActionactionWithTitle:@"是"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction*action) {
[arrayImagesremoveObject:arrayImages[indexPath.item]];
[self.collectionreloadData];
}];
[alertControlleraddAction:action];
UIAlertAction*actionDelete = [UIAlertActionactionWithTitle:@"否"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction*action) {
}];
[alertControlleraddAction:actionDelete];
[selfpresentViewController:alertControlleranimated:YEScompletion:nil];
}
[self.collection reloadData];
}
7.類似滴滴打車軟件中左邊側(cè)滑時動態(tài)隱藏 狀態(tài)欄:
相信細心的朋友會發(fā)現(xiàn),狀態(tài)欄是動態(tài)隱藏了,可是由于缺少狀態(tài)欄的20像素,造成了背部的視圖整體上移了20像素,我使用的是系統(tǒng)自帶的導(dǎo)航欄,也嘗試了動態(tài)增加 導(dǎo)航欄的高度從44變?yōu)?4,可是總有瞬間形變造成的不自然感,最后細心研究發(fā)現(xiàn)**滴滴打車是自定義的導(dǎo)航欄**,所以我使用的方法是沒錯的,只要需要的時候使用自定義的導(dǎo)航欄就可以達到 跟 滴滴打車一樣的效果啦。
關(guān)鍵代碼:
(1) View controller-based status bar appearance設(shè)為NO,這時application的設(shè)置優(yōu)先級最高,用下面的方式隱藏status bar:
[[UIApplicationsharedApplication]setStatusBarHidden:YES ?withAnimation:UIStatusBarAnimationSlide];
(2)如果View controller-based status bar appearance設(shè)為YES。這時view controller中對status bar的設(shè)置優(yōu)先級高于application的設(shè)置,用下面的方式隱藏status bar:
1、在view controller中調(diào)用setNeedsStatusBarAppearanceUpdate,更新status bar的顯示。
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
[self prefersStatusBarHidden];
[self performSelector:@selector(setNeedsStatusBarAppearanceUpdate)];
}}
2、覆蓋view controller的prefersStatusBarHidden的實現(xiàn),返會YES。
- (BOOL)prefersStatusBarHidden
{
return YES;
}
就可以達到動態(tài)隱藏和顯示狀態(tài)欄的目的。
8.朗讀文字
使用到的是 iOS 原聲的? AVFoundation.framework 里面的API。?
使用到的類是 :AVSpeechSynthesizer?里面包括 ?開始、暫停、繼續(xù)朗讀等功能。
所有的嗓音如下:
"[AVSpeechSynthesisVoice 0x978a0b0] Language: th-TH",
"[AVSpeechSynthesisVoice 0x977a450] Language: pt-BR",
"[AVSpeechSynthesisVoice 0x977a480] Language: sk-SK",
"[AVSpeechSynthesisVoice 0x978ad50] Language: fr-CA",
"[AVSpeechSynthesisVoice 0x978ada0] Language: ro-RO",
"[AVSpeechSynthesisVoice 0x97823f0] Language: no-NO",
"[AVSpeechSynthesisVoice 0x978e7b0] Language: fi-FI",
"[AVSpeechSynthesisVoice 0x978af50] Language: pl-PL",
"[AVSpeechSynthesisVoice 0x978afa0] Language: de-DE",
"[AVSpeechSynthesisVoice 0x978e390] Language: nl-NL",
"[AVSpeechSynthesisVoice 0x978b030] Language: id-ID",
"[AVSpeechSynthesisVoice 0x978b080] Language: tr-TR",
"[AVSpeechSynthesisVoice 0x978b0d0] Language: it-IT",
"[AVSpeechSynthesisVoice 0x978b120] Language: pt-PT",
"[AVSpeechSynthesisVoice 0x978b170] Language: fr-FR",
"[AVSpeechSynthesisVoice 0x978b1c0] Language: ru-RU",
"[AVSpeechSynthesisVoice 0x978b210] Language: es-MX",
"[AVSpeechSynthesisVoice 0x978b2d0] Language: zh-HK",? 中文(香港) 粵語
"[AVSpeechSynthesisVoice 0x978b320] Language: sv-SE",
"[AVSpeechSynthesisVoice 0x978b010] Language: hu-HU",
"[AVSpeechSynthesisVoice 0x978b440] Language: zh-TW",? 中文(臺灣)
"[AVSpeechSynthesisVoice 0x978b490] Language: es-ES",
"[AVSpeechSynthesisVoice 0x978b4e0] Language: zh-CN",? 中文(普通話)
"[AVSpeechSynthesisVoice 0x978b530] Language: nl-BE",
"[AVSpeechSynthesisVoice 0x978b580] Language: en-GB",? 英語(英國)
"[AVSpeechSynthesisVoice 0x978b5d0] Language: ar-SA",
"[AVSpeechSynthesisVoice 0x978b620] Language: ko-KR",
"[AVSpeechSynthesisVoice 0x978b670] Language: cs-CZ",
"[AVSpeechSynthesisVoice 0x978b6c0] Language: en-ZA",
"[AVSpeechSynthesisVoice 0x978aed0] Language: en-AU",
"[AVSpeechSynthesisVoice 0x978af20] Language: da-DK",
"[AVSpeechSynthesisVoice 0x978b810] Language: en-US",? 英語(美國)
"[AVSpeechSynthesisVoice 0x978b860] Language: en-IE",
"[AVSpeechSynthesisVoice 0x978b8b0] Language: hi-IN",
"[AVSpeechSynthesisVoice 0x978b900] Language: el-GR",
"[AVSpeechSynthesisVoice 0x978b950] Language: ja-JP" )
代碼:
#import
// 創(chuàng)建嗓音,指定嗓音不存在則返回nil
AVSpeechSynthesisVoice *voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
// 創(chuàng)建語音合成器
AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer alloc] init];
// 實例化發(fā)聲的對象
AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:@"朗讀完畢"];
utterance.voice = voice;
utterance.rate = 0.5; ? ? ? ? // 語速
speech.pitchMultiplier=1; ?//音高 ? 越高聲音越尖
speech.postUtteranceDelay=0.1f;//目的是讓語音合成器播放下一語句前有短暫的暫停
speech.volume=1; ? ? ? ? ? ? //音量
[synthesizer speakUtterance:utterance];? // 朗讀的內(nèi)容
如果提示這種錯誤:
|AXSpeechAssetDownloader|error| ASAssetQuery error fetching results (for com.apple.MobileAsset.MacinTalkVoiceAssets) Error Domain=ASError Code=21 "Unable to copy asset information" UserInfo={NSDescription=Unable to copy asset information}
請去iPhone里設(shè)置:
進入iPhone的 設(shè)置 > 通用 > 輔助功能 > 語音,開啟“朗讀所選項”,并在“嗓音”中選擇“中文”
? ? ?在真機測試的時候,碰巧那臺手機的加減音量按鍵失效了,于是在手機設(shè)置里把音量調(diào)到最大,可是在測試的時候還是音量很小,最后換了一臺手機,在測試的時候使用+-鍵加大了音量,聲音果然大了起來,才發(fā)現(xiàn)手機設(shè)置-> 聲音-> ?設(shè)置的聲音大小是來電鈴聲的音量大小,并不是揚聲器的音量。+-鍵才能設(shè)置的是揚聲器的音量。
9.語音轉(zhuǎn)文字
使用的是第三方 ?科大訊飛的SDK ? ? ??github 地址
10.別人的模擬器運行起我們開發(fā)的app
場景:無法真機裝app| 公司的UUID 已經(jīng)使用完了 |?
解決辦法:
解決思路,想要別人的模擬器運行起我們開發(fā)的app,最簡單的辦法就是把我們DerivedData的數(shù)據(jù)直接拷貝到別人模擬器上面,就可以了。
ditto -ck --sequesterRsrc --keepParent `ls -1 -d -t ~/Library/Developer/Xcode/DerivedData/*/Build/Products/*-iphonesimulator/*.app | head -n 1`?
我們運行完上面的ditto命令會產(chǎn)生一個zip文件,解壓出來,會得到一個app文件,這個就是debug包了。debug包就是我們要給設(shè)計師的app包了。
如何能讓設(shè)計師傻瓜式的安裝這個app呢?這里介紹一個命令行工具,ios-sim命令行工具。
ios-sim 是一個可以在命令控制iOS模擬器的工具。利用這個命令,我們可以啟動一個模擬器,安裝app,啟動app,查詢iOS SDK。它可以使我們像自動化測試一樣不用打開Xcode。