輕松學(xué)習(xí)swift--swift項(xiàng)目初體驗(yàn)(二)

項(xiàng)目源代碼: Photo-Browser

一.傳遞數(shù)據(jù)

1.傳遞什么數(shù)據(jù)?

要在PhotoBrowserVc中查看大圖,首先要拿到圖片數(shù)據(jù)

2.怎么傳遞數(shù)據(jù)?直接傳遞圖片?

直接傳遞圖片url也可以,不過要從模型數(shù)組中抽離出來,不太好
最好的做法是:直接把模型數(shù)組傳遞給PhotoBrowserVc

二.自定義PhotoBrowserCell,用于展示數(shù)據(jù)

1.PhotoBrowserVc是UICollectionViewController,要想展示圖片,需要在cell上添加UIImageView

注意:如果一個(gè)構(gòu)造函數(shù)前有required,那么重寫了其他構(gòu)造函數(shù)時(shí),那么該構(gòu)造函數(shù)也必須被重寫

// MARK:- 重寫構(gòu)造函數(shù)    
override init(frame: CGRect) {        
    super.init(frame: frame)               
    setupUI()    
}    
// required : 如果一個(gè)構(gòu)造函數(shù)前有required,那么重寫了其他構(gòu)造函數(shù)時(shí),那么該構(gòu)造函數(shù)也必須被重寫    
required init?(coder aDecoder: NSCoder) {              
    fatalError("init(coder:) has not been implemented")
}

2.要想展示圖片,需要設(shè)置什么?

2.1 設(shè)置UIImageView的image

直接從 SDWebImage緩存中取出原來cell的圖片(小圖)
注意:取出的圖片類型是可選類型,要先進(jìn)行判斷再使用

2.2 設(shè)置UIImageView的frame

2.21 根據(jù)取出的圖片的尺寸,計(jì)算圖片的frame(設(shè)置UIImageView的寬度等于屏幕寬度)

2.22 讓圖片的寬度等于UIImageView的寬度

2.23 UIImageView的高度,就等于 圖片高度 * UIImageView的寬度 / 圖片寬度 (讓圖片等寬高比拉伸)

3.加載高清圖片

3.1 為什么要加載高清圖片?

上面取出的圖片是小圖,不清晰. 查看大圖的時(shí)候,要換成高清圖片

3.2 怎么設(shè)置?

用SDWebImage加載大圖,把小圖設(shè)置為占位圖片
占位圖片:圖片還沒加載的時(shí)候,先用內(nèi)存中的一張圖片顯示到屏幕上,加載好圖片, 就顯示加載的圖片

4.設(shè)置完成后,查看大圖,發(fā)現(xiàn)滾動(dòng)到后面,發(fā)現(xiàn)圖片被壓縮了,為什么?

4.1 因?yàn)樵贛ainVc(首頁(yè))展示小圖的時(shí)候,給小圖也設(shè)置了占位圖片

4.2 在PhotoBrowserVc中查看大圖,滾動(dòng)到后面的時(shí)候,MainVc中的cell還沒顯示,小圖就不會(huì)被加載,就把占位圖片賦值給小圖

 // 2.獲取小圖片
var smallImage = SDWebImageManager.sharedManager().imageCache.imageFromDiskCacheForKey(shop.q_pic_url)            
if smallImage == nil {                
        smallImage = UIImage(named: "empty_picture")
        }

4.3 這是UIImageView的尺寸就是根據(jù)占位圖片的尺寸計(jì)算出來的,跟實(shí)際圖片的尺寸會(huì)有差別,實(shí)際顯示的圖片就可能被壓縮

5.怎么解決圖片壓縮問題?

大圖請(qǐng)求成功時(shí),重新計(jì)算UIImageView的尺寸就可以了

三.把collectionView滾動(dòng)到正確的位置

1.為什么要滾動(dòng)collectionView?

PhotoBrowserVc的cell是從第0個(gè)cell開始顯示的, 所以每次點(diǎn)擊查看大圖都是從第0張圖片開始顯示
當(dāng)點(diǎn)擊MainVc(首頁(yè))cell的時(shí)候,要顯示對(duì)應(yīng)的大圖,不一定是第0張圖片

2.怎么滾動(dòng)?

2.1 在PhotoBrowserVc中定義indexPath屬性, 在MainVc中拿到cell的indexPath,對(duì) PhotoBrowserVc的indexPath賦值

2.2 滾動(dòng)到對(duì)應(yīng)的位置(用下面這個(gè)方法)

collectionView.scrollToItemAtIndexPath(indexPath!, atScrollPosition: .CenteredHorizontally, animated: false)

2.3 滾動(dòng)代碼應(yīng)該寫到哪里?

點(diǎn)擊MainVc的cell,就彈出查看大圖控制器(PhotoBrowserVc),就要滾動(dòng)要對(duì)應(yīng)的位置
所以,代碼可以寫到viewDidLoad里面

3. ??的使用

  // ?? : 先判斷前面的可選鏈?zhǔn)欠裼兄? 如果有值,解包并且獲取對(duì)應(yīng)類型的值. 如果沒有值直接取后面的值
   return shops?.count ?? 0

四.設(shè)置大圖之間的間距

1.怎么設(shè)置大圖之間的間距?用 minimumLineSpacing?

不可以,雖然能讓大圖之間有間距,但是會(huì)把后面的cell往后移 ,后面的cell就不能完全顯示在屏幕上

2.思考:可以collectionView的cell的寬度比屏幕寬度大一點(diǎn),多出來的寬度就當(dāng)做間距

不可行,collectionView(scrollView)的分頁(yè)效果,會(huì)讓用戶看到多出來的那部分

scrollView分頁(yè)效果的滾動(dòng)距離 是由scrollView的寬度來決定的

3.最終解決方案

3.1 只用一句代碼就可以搞定,把控制器的view的寬度增大一點(diǎn)就可以了

      view.frame.size.with += 15

3.2 注意collectionView的寬度和 cell的寬度 要等于控制器的view的寬度才可以

4.全局函數(shù)的定義

4.1 什么是全局函數(shù)?
就是在工程目錄下的任何地方都能使用的函數(shù)

4.2 怎么定義全局函數(shù)?
只要把函數(shù)定義到AppDelegate里面就可以了

五.保存圖片

1.先要拿到對(duì)應(yīng)的圖片,根據(jù)indexPath拿?

點(diǎn)擊查看大圖后可能會(huì)被滾動(dòng),所以不能根據(jù)indexPath拿

2.怎么拿到正在顯示的圖片

2.1 先拿到正在顯示的cell
2.2 cell里面保存的就有image

3.怎么拿到cell

可以通過蘋果自帶的api拿到正在顯示的cell

// 1.1.拿到正在顯示的Cell        
// visibleCells 返回所有在屏幕中顯示的Cell        
let cell = collectionView.visibleCells()[0] as! PhotoBrowserViewCell        
 guard let image = cell.imageView.image else {            
    return
    }

4.保存圖片到相冊(cè)

蘋果自帶api保存到相冊(cè)

UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)

六.點(diǎn)擊大圖關(guān)閉控制器

1.需求:點(diǎn)擊大圖或關(guān)閉按鈕,把控制器dismiss掉

2.點(diǎn)擊按鈕關(guān)閉
給按鈕設(shè)置點(diǎn)擊方法就可以了 addTarget

3.點(diǎn)擊大圖關(guān)閉怎么實(shí)現(xiàn)?
點(diǎn)擊大圖相當(dāng)于點(diǎn)擊了cell,在cell代理方法里面dismiss即可

七.自定義轉(zhuǎn)場(chǎng)(淡入淡出)

1.怎么自定義轉(zhuǎn)場(chǎng)動(dòng)畫?

遵守轉(zhuǎn)場(chǎng)的代理協(xié)議UIViewControllerTransitioningDelegate,實(shí)現(xiàn)代理方法

2.實(shí)現(xiàn)了代理方法,發(fā)現(xiàn)程序還是報(bào)錯(cuò),為什么?

代理方法都有一個(gè)返回值,返回值要遵守一個(gè)協(xié)議UIViewControllerContextTransitioning才能作為返回值

3.在UIViewControllerContextTransitioning代理方法里面設(shè)置動(dòng)畫(具體看代碼)

4.設(shè)置消失動(dòng)畫

4.1 設(shè)置完顯示動(dòng)畫后,消失的時(shí)候也自動(dòng)會(huì)有一個(gè)動(dòng)畫效果,為什么?
因?yàn)?大圖view消失的時(shí)候,也是主控制器的view顯示的時(shí)候
看到的消失動(dòng)畫,實(shí)際上是主控制器的view的顯示動(dòng)畫

4.2 怎么判斷是顯示,還是消失?

定義一個(gè)屬性記錄即可
在UIViewControllerTransitioningDelegate代理方法中記錄

// MARK:- 遵守轉(zhuǎn)場(chǎng)的代理協(xié)議,和實(shí)現(xiàn)對(duì)應(yīng)的方法
extension HomeViewController : UIViewControllerTransitioningDelegate {    
// 為彈出控制器做一個(gè)動(dòng)畫
func animationControllerForPresentedController(presented: 
UIViewController, presentingController presenting: 
UIViewController, sourceController source: UIViewController) 
-> UIViewControllerAnimatedTransitioning? {

 //記錄當(dāng)前為顯示階段
 isPresented = true
    return self
}

// 為消失控制器做一個(gè)動(dòng)畫
func animationControllerForDismissedController(dismissed: 
UIViewController) -> UIViewControllerAnimatedTransitioning? {

  //記錄當(dāng)前為消失階段
  isPresented = false
    return self    
  }
}

extension HomeViewController : UIViewControllerAnimatedTransitioning {    
// 返回動(dòng)畫執(zhí)行的時(shí)間    
func transitionDuration(transitionContext: 
UIViewControllerContextTransitioning?) 
-> NSTimeInterval {        

return 3    
}        
// transitionContext : 轉(zhuǎn)場(chǎng)上下文    
// 作用 : 可以通過上下文獲取到彈出的View和消失的View    
// UITransitionContextFromViewKey : 獲取消失的View
// UITransitionContextToViewKey : 獲取彈出的View
func animateTransition(transitionContext: 
UIViewControllerContextTransitioning) {       

 if isPresented {            
// 獲取彈出的View
let presentedView = transitionContext.viewForKey(UITransitionContextToViewKey)!
//需要把view添加到父控件上,才能有動(dòng)畫效果  
//父控件就是widow的containerView,   通過transitionContext.containerView()拿到
transitionContext.containerView()?.addSubview(presentedView) 
// 修改View alpha值            
presentedView.alpha = 0.0                       
// 執(zhí)行動(dòng)畫            
UIView.animateWithDuration(transitionDuration(transitionContext), animations: {                
presentedView.alpha = 1.0
}) { (isFinished : Bool) in
//告訴控制器,轉(zhuǎn)場(chǎng)動(dòng)畫完成
transitionContext.completeTransition(isFinished)            
  }        
} else {            
// 1.獲取消失的View            
let dismissedView = transitionContext.viewForKey(UITransitionContextFromViewKey)!  
// 2.執(zhí)行動(dòng)畫            
UIView.animateWithDuration(transitionDuration(transitionContext), animations: {                
    dismissedView.alpha = 0.0
  }, completion: { (isFinished : Bool) in
 //移除view,顯示主控制器的view
       dismissedView.removeFromSuperview()                    
        transitionContext.completeTransition(isFinished)            
      })        
    }   
  }
}

5.性能優(yōu)化,代碼抽取

5.1 把轉(zhuǎn)場(chǎng)動(dòng)畫的代理設(shè)置為主控制器,代理要全部寫在主控制器中,代碼臃腫,閱讀性差

5.2 怎么優(yōu)化?

把代理設(shè)置為其它對(duì)象,讓其它對(duì)象實(shí)現(xiàn)代理方法即可

5.3 具體實(shí)現(xiàn)步驟

5.31 創(chuàng)建一個(gè)對(duì)象(任何對(duì)象)

5.32 設(shè)置這個(gè)對(duì)象為轉(zhuǎn)場(chǎng)動(dòng)畫的代理

5.33 在對(duì)象中實(shí)現(xiàn)代理方法即可

5.34 注意:代理屬性為弱引用,要讓一個(gè)強(qiáng)引用指向它

八.最終動(dòng)畫效果

1.想要做動(dòng)畫,必須要拿到三個(gè)元素

1.1 圖片的起始位置(相對(duì)于控制器view的坐標(biāo)系)

1.2 圖片的終點(diǎn)位置(相對(duì)于控制器view的坐標(biāo)系)

1.3 轉(zhuǎn)場(chǎng)圖片的父控件UIImageView

2.彈出動(dòng)畫

2.1 獲取動(dòng)畫的三個(gè)元素
圖片的起始位置,終點(diǎn)位置和UIImageView 只有主控制器(mainVc)最清楚,可以定義代理

2.2 mainVc成為動(dòng)畫代理對(duì)象的代理,提供三個(gè)元素

3.消失動(dòng)畫

3.1 消失的時(shí)候,圖片的終點(diǎn)位置有可能發(fā)生變化,需要重新計(jì)算

3.2 怎么計(jì)算消失的圖片的終點(diǎn)位置?

只要拿到對(duì)應(yīng)cell的indexPath就可以計(jì)算位置

3.3 怎么拿到indexPath?

cell的indexPath只有PhotoBrowserVc最清楚,可以設(shè)置代理,讓PhotoBrowserVc提供indexPath
indexPath就是最后顯示在屏幕上cell的indexPath

// 1.獲取在屏幕中顯示的cell
let cell = collectionView.visibleCells()[0]  
// 2.獲取cell對(duì)應(yīng)的indexPath
let indexPath = collectionView.indexPathForCell(cell)!

3.4 根據(jù)indexPath計(jì)算終點(diǎn)位置,完成動(dòng)畫

4.性能優(yōu)化

4.1 當(dāng)查看大圖滾動(dòng)的時(shí)候,indexPath會(huì)大于屏幕上顯示的indexPath最大值,這個(gè)時(shí)候,就獲取不到終點(diǎn)位置,就會(huì)沒有消失動(dòng)畫

4.2 怎么解決?

方法一: 當(dāng)超出的時(shí)候,給定一個(gè)終點(diǎn)位置,讓它在指定的位置消失
效果可以,但是滿足不了需求

4.3 最終方案(參考微信的解決方案)

當(dāng)獲取不到終點(diǎn)位置的時(shí)候,讓圖片消失的動(dòng)畫 設(shè)置為漸變消失動(dòng)畫

九.版本適配bug的解決

1.當(dāng)項(xiàng)目運(yùn)行到6s Plus上的時(shí)候,collectionView只能顯示兩列(需求是三列)

產(chǎn)生bug的原因是蘋果對(duì)臨界值得處理不太好

具體來說就是,屏幕寬度三等分,得到的數(shù)值是無限循環(huán)小數(shù),蘋果會(huì)根據(jù)數(shù)據(jù)類型對(duì)小數(shù)向前進(jìn)一位

這時(shí),屏幕的寬度就不足以放三個(gè)cell,就會(huì)把第三個(gè)cell擠到下一行顯示,就變成了兩列

2.bug解決

讓得到的cell的寬度減去一個(gè)臨界值小數(shù)即可(0.000001) 這個(gè)數(shù)值隨便寫

想了解更多請(qǐng)查看:輕松學(xué)習(xí)swift--swift項(xiàng)目初體驗(yàn)(一)

項(xiàng)目源代碼: Photo-Browser
喜歡就給個(gè)星星吧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缸剪,一起剝皮案震驚了整個(gè)濱河市东亦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌典阵,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嫉鲸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡玄渗,警方通過查閱死者的電腦和手機(jī)狸眼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來份企,“玉大人巡莹,你說我怎么就攤上這事〗嫡” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵激才,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我瘸恼,道長(zhǎng),這世上最難降的妖魔是什么东帅? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮靠闭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拦键。我一直安慰自己,他們只是感情好芬为,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布狼钮。 她就那樣靜靜地躺著,像睡著了一般熬芜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上涎拉,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音半火,去河邊找鬼。 笑死钮糖,一個(gè)胖子當(dāng)著我的面吹牛酌住,可吹牛的內(nèi)容都是我干的店归。 我是一名探鬼主播酪我,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼秩伞!你這毒婦竟也來了逞带?” 一聲冷哼從身側(cè)響起纱新,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎带饱,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體勺疼,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡捏鱼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了导梆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡递鹉,死狀恐怖藏斩,靈堂內(nèi)的尸體忽然破棺而出躏结,到底是詐尸還是另有隱情狰域,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布兆览,位于F島的核電站,受9級(jí)特大地震影響抬探,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜砰左,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一场航、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧溉痢,春花似錦僻造、人聲如沸孩饼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宝泵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間儿奶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工闯捎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留许溅,地道東北人瓤鼻。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蛮艰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蚀狰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,105評(píng)論 4 62
  • 概述在iOS開發(fā)中UITableView可以說是使用最廣泛的控件陪每,我們平時(shí)使用的軟件中到處都可以看到它的影子,類似...
    liudhkk閱讀 9,047評(píng)論 3 38
  • 本來是打算開學(xué)后就給你寫一封信的檩禾,但是一直因?yàn)樽约旱脑虬碳溃恢睕]有寫成盼产,今晚以簡(jiǎn)書的名義代替信吧勺馆。 1侨核、若不曾體會(huì)...
    琉璃木子李閱讀 477評(píng)論 0 2
  • 重新看了一遍《悟空傳》 然后去操場(chǎng)跑了五公里 人生第一次必須要嘚瑟 聽的是郭燕的《天空之城》 調(diào)子太悲書也悲心里自...
    舊時(shí)咸陽閱讀 346評(píng)論 0 0
  • 1锋喜、什么是cocoaPods cocoaPods是開發(fā)OS X和iOS應(yīng)用程序的一個(gè)第三方庫(kù)的依賴管理工具 2,為...
    禪牧閱讀 850評(píng)論 10 2