UICollectionView Tutorial Part 2:Reusable Views and Cell Selection

上一篇中,你學(xué)到了如何來用UICollectionView完成一個網(wǎng)格相冊.
在本篇中,你將繼續(xù)來學(xué)習(xí)collection views的更多用法.繼續(xù)使用上一篇的項(xiàng)目或者可以在這里下載(你需要上一篇提到的新的API key).

  • 添加標(biāo)頭
    這個應(yīng)用每個搜索結(jié)果都有一個section.可以在搜索結(jié)果之前添加一個標(biāo)頭,以便更好地顯示照片信息.
    使用UICollectionReusableView來創(chuàng)建標(biāo)頭.這個類是collection view cell的一種(實(shí)際上,cells繼承于此類),但用法卻同headers或footers相似.
    這個view可以在storyboard里創(chuàng)建并可以連接到你的類中.新建一個UICollectionReusableView的子類,命名為FlickrPhotoHeaderView.
    在collection view的Attributes Inspector里面勾選Section Header:

Screen-Shot-2012-09-23-at-3.08.56-PM.png

你會發(fā)現(xiàn)"Collection Reusable View"將自動添加到Collection View的下面.選擇Collection Reusable View后就可以添加子視圖了.
你可以通過拖動Collection Reusable View的底部來使其變?yōu)?0pixels高,便于有更多的空間.(你也可以在屬性面板里改變view的尺寸)
在header view的中心添加一個label控件.將字體調(diào)為System 32.0并在alignment menu里添加水平和豎直相關(guān)的約束,更新frame:

Labelalignments.png

選擇頭視圖,將其Class設(shè)為FlickrPhotoHeaderView.
設(shè)置背景顏色為90%的白色,視圖的Identifier設(shè)為FlickrPhotoHeaderView.這個identifier將會在下面用到.
點(diǎn)擊Assistant editor,確保FlickrPhotoHeaderView.swift打開,連線拖拽label到類中.命名為label:

class FlickrPhotoHeaderView: UICollectionReusableView {
  @IBOutlet weak var label: UILabel!
}

如果現(xiàn)在就運(yùn)行程序,你將看不到header(或者將是個僅有個"Label"文字的空白頁).你需要實(shí)現(xiàn)另外的一個datasource 方法.打開FlickrPhotosViewController.swift添加UICollectionViewDataSource擴(kuò)展:

override func collectionView(collectionView: UICollectionView,
  viewForSupplementaryElementOfKind kind: String,
  atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
    //1
    switch kind {
      //2
      case UICollectionElementKindSectionHeader:
        //3
        let headerView =
        collectionView.dequeueReusableSupplementaryViewOfKind(kind,
          withReuseIdentifier: "FlickrPhotoHeaderView",
          forIndexPath: indexPath)
          as! FlickrPhotoHeaderView
        headerView.label.text = searches[indexPath.section].searchTerm
        return headerView
      default:
        //4
        assert(false, "Unexpected element kind")
    }
}

這個方法和cellForItemAtIndexPath相似,但卻視為額外的視圖所用的.下面是以上代碼的釋義:

  1. kind參數(shù)由布局對象提供并標(biāo)明是哪個額外的視圖.
  2. UICollectionElementKindSectionHeader為flow layout提供的一種額外視圖.通過添加storyboard中的屬性來告訴flow layout需要額外的視圖,因此添加了個section header.當(dāng)然也有UICollectionElementKindSectionFooter,但現(xiàn)在并沒有用到.如果你使用的不是flow layout,并不會這么容易就添加header和footer.
  3. header通過storyboard中的identifier來標(biāo)示.原理同cell相似.label上的文字被設(shè)置為相關(guān)的搜索項(xiàng)目.
  4. 斷言在這里是提醒后來的開發(fā)者(或者是將來的你),這里并不想得到除header view外的對象.

運(yùn)行程序,你會看到UI快完成了.如果你進(jìn)行了多個搜索,你將會得到section headers來很好地分隔你的搜索結(jié)果.翻轉(zhuǎn)設(shè)配你會發(fā)現(xiàn)無需額外的工作,各個布局都看起來很不錯.

collectionviewheaders-666x500.png
  • Cell的交互
    在最后,你將學(xué)到cell的一些交互.你將完成兩種不同的操作.一種是放大圖片,一種是多選圖片來分享.

  • 單個選擇
    Collection能夠通過動畫來變化它的布局.第一個任務(wù)是點(diǎn)擊時圖片放大.
    首先,你需要添加一個屬性來表示你點(diǎn)擊的cell.打開FlickrPhotosViewController.swift,添加如下代碼:

//1
var largePhotoIndexPath : NSIndexPath? {
didSet {
  //2
  var indexPaths = [NSIndexPath]()
  if largePhotoIndexPath != nil {
    indexPaths.append(largePhotoIndexPath!)
  }
  if oldValue != nil {
    indexPaths.append(oldValue!)
  }
  //3
      collectionView?.performBatchUpdates({
        self.collectionView?.reloadItemsAtIndexPaths(indexPaths)
        return
        }){
          completed in
          //4
          if self.largePhotoIndexPath != nil {
            self.collectionView?.scrollToItemAtIndexPath(
              self.largePhotoIndexPath!,
              atScrollPosition: .CenteredVertically,
              animated: true)
          }
      }
  }
}

下面是代碼的釋義:

  1. largePhotoIndexPath為點(diǎn)擊圖片的index path.
  2. 當(dāng)此屬性被更新時,collection view需要更新.didSet屬性表明這是個安全的地方來處理這些更新.如果用戶已經(jīng)點(diǎn)擊了一幅圖片后再點(diǎn)擊另一幅,或者點(diǎn)擊相同一副圖兩次則需要縮放動畫,這時需要兩個cells重載.
  3. 更新動畫完成后,最好將放大的圖片放在屏幕中央.

"如何來增大Cell鲤拿?"待會告訴你.
點(diǎn)擊cell時會將collection view選中.你將通過設(shè)置的largeIndexPath屬性來獲取你點(diǎn)擊的cell,但你并不希望這個cell真正被選中,當(dāng)你使用多選時這將會是你迷惑.collection view 通過代理方法來判斷是否選中了一個cell.仍然在FlickrPhotosViewController.swift添加一個新的擴(kuò)展方法來增加collection view的代理方法,如下:

extension FlickrPhotosViewController : UICollectionViewDelegate {
 
  override func collectionView(collectionView: UICollectionView,
    shouldSelectItemAtIndexPath indexPath: NSIndexPath) -> Bool {
      if largePhotoIndexPath == indexPath {
        largePhotoIndexPath = nil
      }
      else {
        largePhotoIndexPath = indexPath
      }
      return false
  }
}

這個方法相當(dāng)簡單.如果這個cell已經(jīng)是大圖了,設(shè)置largePhotoIndexPath為nil,相反地,設(shè)置其index path為所點(diǎn)擊的.這將會調(diào)用之前你添加的屬性觀察者來使collection view更新重載.
要實(shí)現(xiàn)點(diǎn)擊cell方法圖片,需要修改flow layout的代理方法sizeForItemAtIndexPath.替換成一下代碼:

func collectionView(collectionView: UICollectionView,
  layout collectionViewLayout: UICollectionViewLayout,
  sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
 
  let flickrPhoto = photoForIndexPath(indexPath)
 
  // New code
  if indexPath == largePhotoIndexPath {
    var size = collectionView.bounds.size
    size.height -= topLayoutGuide.length
    size.height -= (sectionInsets.top + sectionInsets.right)
    size.width -= (sectionInsets.left + sectionInsets.right)
    return flickrPhoto.sizeToFillWidthOfSize(size)
  }
  // Previous code
  if var size = flickrPhoto.thumbnail?.size {
    size.width += 10
    size.height += 10
    return size
  }
  return CGSize(width: 100, height: 100)
}

添加的方法用來計(jì)算放大后的尺寸.
沒必要更大的cell除非你有更大的圖片需要真實(shí).
在Main.storyboard的collection view cell里面image view上添加一個activity indicator.將這個activity indicator 的Style設(shè)置為Large White,勾選Hides When Stopped.將它放于cell的中央,添加約束.

cellcontents.png

將activity indicator在FlickrPhotoCell.swift中添加對應(yīng)的outlet,命名為activityIndicator:

  @IBOutlet weak var activityIndicator: UIActivityIndicatorView!

然后在FlickrPhotoCell.swift中添加如下代碼來控制cell的背景色:

override func awakeFromNib() {
  super.awakeFromNib()
  self.selected = false
}
 
override var selected : Bool {
  didSet {
    self.backgroundColor = selected ? themeColor : UIColor.blackColor()
  }
}

最后需要更新FlickrPhotosCollectionViewController.swift里的cellForItemAtIndexPath:

override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
 
  let cell = collectionView.dequeueReusableCellWithReuseIdentifier(
    reuseIdentifier, forIndexPath: indexPath) as! FlickrPhotoCell
  let flickrPhoto = photoForIndexPath(indexPath)
 
  //1
  cell.activityIndicator.stopAnimating()
 
  //2
  if indexPath != largePhotoIndexPath {
    cell.imageView.image = flickrPhoto.thumbnail
    return cell
  }
 
  //3
  if flickrPhoto.largeImage != nil {
    cell.imageView.image = flickrPhoto.largeImage
    return cell
  }
 
  //4
  cell.imageView.image = flickrPhoto.thumbnail
  cell.activityIndicator.startAnimating()
 
  //5
  flickrPhoto.loadLargeImage {
    loadedFlickrPhoto, error in
 
    //6
    cell.activityIndicator.stopAnimating()
 
    //7
    if error != nil {
      return
    }
 
    if loadedFlickrPhoto.largeImage == nil {
      return
    }
 
    //8
    if indexPath == self.largePhotoIndexPath {
      if let cell = collectionView.cellForItemAtIndexPath(indexPath) as? FlickrPhotoCell {
        cell.imageView.image = loadedFlickrPhoto.largeImage
      }
    }
  }
 
  return cell
}

下面為以上代碼的釋義:

  1. 總是停止activity spinner - 你需要復(fù)用cell在圖片下載之前.
  2. 這部分和之前相同 - 如果你沒有查看大圖片,僅設(shè)置返回thumbnail即可.
  3. 如果大圖片已經(jīng)加載完,返回它
  4. 當(dāng)你想要獲得大圖片,但還沒有時,設(shè)置spinner運(yùn)轉(zhuǎn)并通過thumbnail image獲取圖片,當(dāng)下載完后縮略圖將會被方法.
  5. 異步請求大圖片并通過block來返回結(jié)果.
  6. 加載完成后,停止spinner.
  7. 如果發(fā)生錯誤或沒有圖片加載,將不做什么.
  8. 檢查放大圖片的index path在下載時是否變化,獲得正確的cell的index path使圖片放大.

運(yùn)行程序,進(jìn)行搜索,點(diǎn)擊你喜歡的圖片,它將填滿屏幕,其它的cell將為它騰出足夠的空間.

largeimages-666x500.png

再次點(diǎn)擊cell,或者滑動后點(diǎn)擊其它c(diǎn)ell.無需寫任何代碼,collection view會完成布局變化的動畫.

Girl學(xué)iOS100天 第14天

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末僧界,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子肿轨,更是在濱河造成了極大的恐慌忍弛,老刑警劉巖戒财,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咽斧,死亡現(xiàn)場離奇詭異阅束,居然都是意外死亡呼胚,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門息裸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蝇更,“玉大人,你說我怎么就攤上這事界牡〔炯牛” “怎么了漾抬?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵宿亡,是天一觀的道長。 經(jīng)常有香客問我纳令,道長挽荠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任平绩,我火速辦了婚禮圈匆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捏雌。我一直安慰自己跃赚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布性湿。 她就那樣靜靜地躺著纬傲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪肤频。 梳的紋絲不亂的頭發(fā)上叹括,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機(jī)與錄音宵荒,去河邊找鬼汁雷。 笑死,一個胖子當(dāng)著我的面吹牛报咳,可吹牛的內(nèi)容都是我干的侠讯。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼暑刃,長吁一口氣:“原來是場噩夢啊……” “哼继低!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起稍走,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤袁翁,失蹤者是張志新(化名)和其女友劉穎柴底,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粱胜,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柄驻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了焙压。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸿脓。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖涯曲,靈堂內(nèi)的尸體忽然破棺而出野哭,到底是詐尸還是另有隱情,我是刑警寧澤幻件,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布拨黔,位于F島的核電站,受9級特大地震影響绰沥,放射性物質(zhì)發(fā)生泄漏篱蝇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一徽曲、第九天 我趴在偏房一處隱蔽的房頂上張望零截。 院中可真熱鬧,春花似錦秃臣、人聲如沸涧衙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弧哎。三九已至,卻和暖如春得院,著一層夾襖步出監(jiān)牢的瞬間傻铣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工祥绞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留非洲,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓蜕径,卻偏偏與公主長得像两踏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子兜喻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫梦染、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,022評論 4 62
  • 嗯哼嗯哼蹦擦擦~~~ 轉(zhuǎn)載自:https://github.com/Tim9Liu9/TimLiu-iOS 目錄 ...
    philiha閱讀 4,844評論 0 6
  • “如果你渴求一滴水,我愿意傾其一片海帕识;如果你要摘一片紅葉泛粹,我給你整個楓林和云彩;如果你要一個微笑肮疗,我敞開火熱的胸懷...
    嚴(yán)紅玉閱讀 248評論 0 0
  • 《家有兒女》伪货,是兩個家庭重組后幸福生活的故事叫搁。 其實(shí)乘寒,孩子要的不是一個名義上的完整的家, 而是父母的愛夹供。 家庭教育...
    愛作夢的魚兒閱讀 625評論 0 1
  • 敏探春 探春其人 探春是賈政的女兒雹洗。府里稱她“三小姐”输瓜,應(yīng)該不是按賈政家算的科雳,因?yàn)橘Z政有五個兒女:賈珠辩越、元春、寶玉...
    葵口小盞閱讀 2,245評論 11 3