国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

iOS高仿城覓應(yīng)用客戶端項(xiàng)目(開發(fā)思路和代碼)

2019-11-14 18:16:27
字體:
供稿:網(wǎng)友

 


這是一款非常完整的一個(gè)ios項(xiàng)目,基本實(shí)現(xiàn)了我們常用的一些功能了,而且界面設(shè)計(jì)個(gè)人感覺還是挺不錯(cuò)的,是一個(gè)不錯(cuò)的學(xué)習(xí)ios項(xiàng)目,喜歡的朋友可以參考一下吧。

項(xiàng)目展示,由于沒有數(shù)據(jù),所以所有的cell顯示的都是我自己寫的數(shù)據(jù)。

源碼下載:

 

 


抽屜

 


首頁部分效果

 

 

首頁效果

 

部分效果

 

發(fā)現(xiàn)

 

消息


搜索

 

 

設(shè)置

 

模糊效果

 

代碼注釋展示

 

代碼注釋展示


還有很多細(xì)節(jié)就不一一展示了,大家將代碼運(yùn)行下自己查看即可。由于內(nèi)容比較多,我就按功能模塊來介紹給大家了。


首先是左邊抽屜的效果以及點(diǎn)擊按鈕切換控制器


  • 實(shí)際這里相當(dāng)于自己定義一個(gè)和系統(tǒng)UITabBarController差不多功能的控件,在最底層有一個(gè)控制器(后面稱之為主控制器),將左邊的按鈕view添加到主控制器的view上,創(chuàng)建好右邊有所的控制器(首頁,發(fā)現(xiàn),消息,設(shè)置...)并且將每個(gè)右邊控制器包裝一個(gè)導(dǎo)航控制器,將導(dǎo)航控制器按序添加給主控制器做子控制器,默認(rèn)情況下將首頁的導(dǎo)航控制器的view添加給主控制器的view子控件,根據(jù)左邊按鈕的點(diǎn)擊事件通過代理方法.移除舊控制器view從父視圖,將新的view添加到主視圖的view具體代碼如下,用一個(gè)臨時(shí)屬性之前選中的控制器
//暫時(shí)先做沒有登陸的情況的點(diǎn)擊
WNXNavigationController *newNC = self.childViewControllers[toIndex];
if (toIndex == WNXleftButtonTypeIcon) {
newNC = self.childViewControllers[fromIndex];
}
//移除舊的控制器view
WNXNavigationController *oldNC = self.childViewControllers[fromIndex];
[oldNC.view removeFromSuperview];
//添加新的控制器view
[self.view addSubview:newNC.view];
newNC.view.transform = oldNC.view.transform;
self.showViewController = newNC.childViewControllers[0];


這樣就完成了切換控制器


  • 抽屜的效果是通過給控制器view做形變動(dòng)畫完成的,由于每個(gè)導(dǎo)航控制器的功能一樣,這里抽取了共同的特點(diǎn)封裝了一個(gè)基類導(dǎo)航控制器,點(diǎn)擊左邊的按鈕完成抽屜效果
  • 拖動(dòng)手勢是給主控制器添加一個(gè)UipanGestureRecognizer手勢,根據(jù)拖動(dòng)的距離計(jì)算出該停留在哪里的位置,這里判斷很多,具體實(shí)現(xiàn)我在代碼中每一步都有注釋,參照代碼即可

首頁


  • 首頁就是一個(gè)tableView就可以搞定,tableView的headView顏色和數(shù)據(jù)服務(wù)器會(huì)給返回,給每個(gè)headView添加一個(gè)點(diǎn)擊手勢,點(diǎn)擊push到下一個(gè)控制器,導(dǎo)航條的顏色會(huì)和前一個(gè)headView的顏色一樣,,這里由于我之前設(shè)置了導(dǎo)航控制器的主題
[UINavigationBar appearanceWhenContainedIn:self, nil]
  • 以不可以直接設(shè)置導(dǎo)航條的顏色了 這里我嘗試了設(shè)置navigationBar的背景色,設(shè)置navigationBar的setTintColor:

設(shè)置navigationBar.layer的背景色 以及根據(jù)顏色畫出navigationBar的背景圖片4種辦法都無法達(dá)到原生的效果


最后采用將navigationBar隱藏,自己放一個(gè)View了冒充導(dǎo)航條來解決這個(gè)問題


發(fā)現(xiàn)


  • 這個(gè)頁面是一個(gè)UICollectionView,里面有兩組數(shù)據(jù),每一組都一個(gè)一個(gè)headView,需要注意的就是cell的點(diǎn)擊事件,這里注意了下官方的做法是不論點(diǎn)擊了cell的哪個(gè)位置,都會(huì)使cell內(nèi)部的button進(jìn)入高亮狀態(tài),這里需要用到事件的響應(yīng)鏈,在cell的內(nèi)部攔截整個(gè)cell的點(diǎn)擊事件都交給按鈕來做,具體代碼如下
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
/* 攔截事件響應(yīng)者,不論觸發(fā)了cell中的哪個(gè)控件都交給iconButton來響應(yīng) */
// 1.判斷當(dāng)前控件能否接收事件
if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil;
// 2. 判斷點(diǎn)在不在當(dāng)前控件
if ([self pointInside:point withEvent:event] == NO) return nil;
return self.iconButton;
}

但 這里需要注意這樣攔截cell的點(diǎn)擊事件,在collectionView的cell被點(diǎn)擊觸發(fā)didDeselectItemAtIndexPath: 就不會(huì)被觸發(fā)了,我的解決方法是在點(diǎn)擊button時(shí)通過代理方法傳給collectionView,外部在通過知道點(diǎn)擊了那個(gè)cell,push到下一 個(gè)控制器,并將cell的model賦值給下一個(gè)控制器


登陸(登陸只用了微信和新浪登陸,不涉及到注冊就非常簡單,這些只需去官網(wǎng)下來登陸和分享的sdk集成進(jìn)來即可,我一般使用友盟平臺(tái),包括崩潰統(tǒng)計(jì),三方登陸,分享,用戶分析等等)


消息


  • 一樣這里也是tabelView,這里我個(gè)人的邏輯是將所有的消息歸檔到本地,每次點(diǎn)擊刪除一條,將本地的數(shù)據(jù)刪除一條,重新歸檔

當(dāng)點(diǎn)擊刪除全部的時(shí)候,就清空本地的歸檔數(shù)據(jù),下次接受的服務(wù)器的數(shù)據(jù)在重新寫入


因?yàn)槭悄M的數(shù)據(jù),為了保障每次進(jìn)來都有數(shù)據(jù),就沒有實(shí)現(xiàn)歸檔解檔的操作,所以每次刪除后重新進(jìn)入會(huì)再次有數(shù)據(jù)


  • 這里記錄編輯按鈕的狀態(tài),讀取本地是否有未讀消息數(shù)組的個(gè)數(shù),如果有就顯示編輯按鈕,記錄編輯按鈕的狀態(tài),如果是選中狀態(tài)就隱藏>圖片,顯示刪除按鈕,點(diǎn)擊刪除按鈕就將本地的數(shù)據(jù)數(shù)組刪除掉并且刷新tableView,這里用的是刪除動(dòng)畫,需要注意刪除的順序
[self.datas removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
  • 底部的刪除全部按鈕完全交給編輯按鈕來控制.


搜索


搜索

 


  • 這個(gè)也需要持久化存儲(chǔ)功能,每次頁面彈出后,先從本地讀取用戶歷史搜索的數(shù)據(jù),用戶每次刪除或者新輸入收縮內(nèi)容時(shí)也直接寫入到本地的caches文件中
  • 這里需要提一下關(guān)于熱門按鈕的布局,因?yàn)闊衢T的文字長度不一樣,但每次只有4個(gè)按鈕,在xib中先將按鈕的位置約束好,不過寬度的約束需要倆個(gè),一個(gè)是>= 和<= 然后根據(jù)服務(wù)器返回的實(shí)際長度在設(shè)置按鈕title時(shí),計(jì)算出每個(gè)按鈕的真實(shí)寬度,根據(jù)真實(shí)寬度算出間距是多少,重新布局一次按鈕的位置
(void)setHotDatas:(NSMutableArray *)hotDatas
{
_hotDatas = hotDatas;
//判斷是長度是否是4,開發(fā)中可以這樣寫 應(yīng)該服務(wù)器返回幾條數(shù)據(jù)就賦值多少,而不是固定的寫死數(shù)據(jù),
//萬一服務(wù)器返回的數(shù)據(jù)有錯(cuò)誤,會(huì)造成用戶直接閃退的,有
//時(shí)在某些不是很重要的東西無法確定返回的是否正確,建議用
//@try @catch來處理,
//即便返回的數(shù)據(jù)有誤,也可以讓用戶繼續(xù)別的操作,
//而不會(huì)在無關(guān)緊要的小細(xì)節(jié)上造成閃退
if (hotDatas.count == 4) {
[self.hotButton1 setTitle:hotDatas[1] forState:UIControlStateNormal];
[self.hotButton2 setTitle:hotDatas[0] forState:UIControlStateNormal];
[self.hotButton3 setTitle:hotDatas[2] forState:UIControlStateNormal];
[self.hotButton4 setTitle:hotDatas[3] forState:UIControlStateNormal];
}
[self layoutIfNeeded];
//算出間距
CGFloat margin = (WNXAppWidth - 40 -
self.hotButton1.bounds.size.width -
self.hotButton2.bounds.size.width -
self.hotButton3.bounds.size.width -
self.hotButton3.bounds.size.width) / 3;
//更新約束
[self.hotButton2 updateConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.hotButton1.right).offset(margin);
}];
[self.hotButton3 updateConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.hotButton2.right).offset(margin);
}];
[self.hotButton4 updateConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.hotButton3.right).offset(margin);
}];
}

模糊效果

 

模糊效果


  • 這里由于圖片的質(zhì)量被壓縮的太厲害,實(shí)際的效果還不錯(cuò),這個(gè)功能是iOS8新開放的接口,有倆個(gè)圖片特效可以使用,一個(gè)是模糊blur,一個(gè)是顏色疊加(類似于PS中圖片疊加的效果,不過就3種效果)

詳情頁


詳情頁展示

 


  • 這個(gè)頁面挺坑的,需要注意的細(xì)節(jié)太多,也是我耗時(shí)最久的頁面,誠然目前bug依舊不少
  • 這個(gè)頁面的層級關(guān)系很重要,需要重點(diǎn)注意
  • 首先是導(dǎo)航條,這個(gè)咋一看好像是導(dǎo)航條有個(gè)漸隱漸現(xiàn)的動(dòng)畫,我的做法是在頂部放了一個(gè)高度為64的view,根據(jù)tableView的偏移量計(jì)算出view的透明度,但是透明度只是1或者0,頂部的scrollView里面裝的imageView,根據(jù)服務(wù)器返回的圖片地址個(gè)數(shù),設(shè)置他的展示內(nèi)容大小,并且在整一個(gè)scrollView最上面添加一個(gè)和導(dǎo)航條一樣顏色的view,用它來做出向上推出現(xiàn)綠色的效果,并且根據(jù)底部scrollview的偏移計(jì)算拉伸的大小,我這里拉伸的大小不是很準(zhǔn)確,感覺需要將錨點(diǎn)釘在最頂端。
  • 然后是中間切換tableView的view(后面就叫它選擇view),要實(shí)現(xiàn)能像headView一樣,卡在導(dǎo)航條下面的效果,這里因?yàn)闆]有導(dǎo)航條,并且在切換tableView時(shí)候不會(huì)帶走選擇view,所以只能將他放到和頂部的view在同一個(gè)層級中,同樣根據(jù)底部scrollView的contentOffset.y計(jì)算他的位置,當(dāng)偏移量超過頂部的64時(shí),就停留在那,不超過時(shí)就回到頂部view的下面,這里的計(jì)算我加了很多的注釋,怕計(jì)算的朋友也會(huì)看的懂的,大概是這樣
  • 下面是一個(gè)scrollView上添加了3個(gè)tabelView,根據(jù)服務(wù)器返回的數(shù)據(jù)判斷顯示多少個(gè),這里就指顯示了倆個(gè),并且第二個(gè)頁面還沒有來得及做

 

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView == self.rmdTableView || scrollView == self.infoTableView) {//說明是tableView在滾動(dòng)
//記錄當(dāng)前展示的是那個(gè)tableView
self.showingTableView = (UITableView *)scrollView;
//記錄出上一次滑動(dòng)的距離,因?yàn)槭窃趖ableView的contentInset中偏移的ScrollHeadViewHeight,所以都得加回來
CGFloat offsetY = scrollView.contentOffset.y;
CGFloat seleOffsetY = offsetY - self.scrollY;
self.scrollY = offsetY;
//修改頂部的scrollHeadView位置 并且通知scrollHeadView內(nèi)的控件也修改位置
CGRect headRect = self.topView.frame;
headRect.origin.y -= seleOffsetY;
self.topView.frame = headRect;
//根據(jù)偏移量算出alpha的值,漸隱,當(dāng)偏移量大于-180開始計(jì)算消失的值
CGFloat startF = -180;
//初始的偏移量Y值為 頂部倆個(gè)控件的高度
CGFloat initY = SelectViewHeight + ScrollHeadViewHeight;
//缺少的那一段漸變Y值
CGFloat lackY = initY + startF;
//自定義導(dǎo)航條高度
CGFloat naviH = 64;
//漸隱alpha值
CGFloat alphaScaleHide = 1 - (offsetY + initY- lackY) / (initY- naviH - SelectViewHeight - lackY);
//漸現(xiàn)alph值
CGFloat alphaScaleShow = (offsetY + initY - lackY) / (initY - naviH - SelectViewHeight - lackY) ;
if (alphaScaleShow >= 0.98) {
//顯示導(dǎo)航條
[UIView animateWithDuration:0.04 animations:^{
self.naviView.alpha = 1;
}];
} else {
self.naviView.alpha = 0;
}
self.topScrollView.naviView.alpha = alphaScaleShow;
self.subTitleLabel.alpha = alphaScaleHide;
self.smallImageView.alpha = alphaScaleHide;
/* 這段代碼很有深意啊。。最開始是直接用偏移量算的,但是回來的時(shí)候速度比較快時(shí)偏移量會(huì)偏度很大
然后就悲劇了。換了好多方法。。最后才開竅T——T,這一段我會(huì)在blog里面詳細(xì)描述我用的各種錯(cuò)誤的方法
用了KVO監(jiān)聽偏移量的值,切換了selectView的父控件,切換tableview的headView。。。
*/
if (offsetY >= -(naviH + SelectViewHeight)) {
self.selectView.frame = CGRectMake(0, naviH, WNXAppWidth, SelectViewHeight);
} else {
self.selectView.frame = CGRectMake(0, CGRectGetMaxY(self.topView.frame), WNXAppWidth, SelectViewHeight);
}
CGFloat scaleTopView = 1 - (offsetY + SelectViewHeight + ScrollHeadViewHeight) / 100;
scaleTopView = scaleTopView > 1 ? scaleTopView : 1;
//算出頭部的變形 這里的動(dòng)畫不是很準(zhǔn)確,好的動(dòng)畫是一點(diǎn)一點(diǎn)試出來了 這里可能還需要配合錨點(diǎn)來進(jìn)行動(dòng)畫,關(guān)于這種動(dòng)畫我會(huì)在以后單開一個(gè)項(xiàng)目配合blog來講解的 這里這就不細(xì)調(diào)了
CGAffineTransform transform = CGAffineTransformMakeScale(scaleTopView, scaleTopView );
CGFloat ty = (scaleTopView - 1) * ScrollHeadViewHeight;
self.topView.transform = CGAffineTransformTranslate(transform, 0, -ty * 0.2);
//記錄selectViewY軸的偏移量,這個(gè)是用來計(jì)算每次切換tableView,讓新出來的tableView總是在頭部用的,
//現(xiàn)在腦子有點(diǎn)迷糊 算不出來了。。凌晨2.57分~
CGFloat selectViewOffsetY = self.selectView.frame.origin.y - ScrollHeadViewHeight;
if (selectViewOffsetY != -ScrollHeadViewHeight && selectViewOffsetY = (0.5 + index)) {
[self.selectView lineToIndex:index + 1];
} else if (seleOffsetX < 0 && offsetX / WNXAppWidth <= (0.5 + index)) {
[self.selectView lineToIndex:index];
}
}
}

這些就是這個(gè)項(xiàng)目的大體思路,當(dāng)然還有很多很多的細(xì)節(jié)都在代碼中,第一次嘗試將思路寫出來,感覺有很多不足,本應(yīng)該每寫完一個(gè)功能就總結(jié)一下,而我是在發(fā)布的晚上回頭總結(jié)的,有很多當(dāng)時(shí)的思路不是很清晰了...


請直接打開WNXHuntForCity.xcworkspace

 

打開


而不要打開WNXHuntForCity.xcodePRoj




詳細(xì)說明:http://ios.662p.com/thread-2519-1-1.html


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 宾阳县| 渝北区| 金昌市| 丽水市| 万盛区| 屏东县| 泉州市| 普兰县| 邢台市| 莱阳市| 蒙山县| 芮城县| 义乌市| 正安县| 成都市| 迭部县| 安康市| 灵川县| 漳浦县| 保山市| 浦东新区| 历史| 湖州市| 阿克| 双城市| 威信县| 西贡区| 孝义市| 福鼎市| 盘山县| 福清市| 贵溪市| 鄂托克前旗| 陕西省| 曲水县| 永年县| 巴林左旗| 贵阳市| 尚志市| 沂南县| 黔江区|