實踐-小效果 Ⅰ

一些小的功能點,雖然很小,但是里面有些彎,值得注意。(同系列文章會持續(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。

原文鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容