日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Swift:用UICollectionView整一个瀑布流

發(fā)布時(shí)間:2024/4/17 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Swift:用UICollectionView整一个瀑布流 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
本文的例子和Swift版本是基于Xcode7.2的。以后也許不知道什么時(shí)候會更新。

我們要干點(diǎn)啥

用新浪微博的Open API做后端來實(shí)現(xiàn)我們要提到的功能。把新浪微博的內(nèi)容,圖片和文字展示在collection view中。本文只簡單的展示內(nèi)容。下篇會用pinterest一樣的效果來展示這些內(nèi)容。

我們準(zhǔn)備優(yōu)先展示圖片。你的好友花了那么多時(shí)間拍照或者從相冊里選擇圖片發(fā)上來多不容易。如果微博返回的數(shù)據(jù)中有中等大小的縮略圖,那么久展示這個(gè)縮略圖。否則的話顯示文本。文本都沒有的話。。。這個(gè)就不是微博了。但是我們還是會準(zhǔn)備一個(gè)顏色顯示出來。

啥是UICollectionView

UICollectionView有一個(gè)靈活的布局,可以用各種不同的布局展示數(shù)據(jù)。?
UICollectionView的使用和UITableView類似,也是需要分別去實(shí)現(xiàn)一組datasource的代理和UICollectionView本身的代理來把數(shù)據(jù)展示在界面中。

UICollectionView也是UIScrollView的一個(gè)子類

其他的還有:?
1. UICollectionViewCell:這些Cell組成了整個(gè)UICollectionView,并作為子View添加到UICollectionView中。可以在Interface builder中創(chuàng)建,也可以代碼創(chuàng)建。?
2. Header/Footer:跟UITableView差不多的概念。顯示一些title什么的信息。

UICollectionView還有一個(gè)叫做Decoration view的東西。顧名思義,主要是裝飾用的。 不過要用這部分的功能你需要單獨(dú)寫定制的layout。

除了以上說到的內(nèi)容之外,collection view還有一個(gè)專門處理布局的UICollectionViewLayout。你可以繼承UICollectionViewLayout來創(chuàng)建一個(gè)自己的collection view的布局。蘋果給了一個(gè)基礎(chǔ)的布局UICollectionViewFlowLayout,可以實(shí)現(xiàn)一個(gè)基本的流式布局。這些會在稍后的教程中介紹。

開始我們的項(xiàng)目:?
首先創(chuàng)建一個(gè)single view的應(yīng)用。?

然后給你的項(xiàng)目起一個(gè)名字,我們這里就叫做CollectionViewDemo。Storyboard中默認(rèn)生成的Controller已經(jīng)木有什么用處了。直接干掉,拖一個(gè)UICollectionViewController進(jìn)去并設(shè)置為默認(rèn)的Controller。并刪除默認(rèn)生成的ViewController.swift文件,并創(chuàng)建一個(gè)叫做HomeCollectionViewController.swift的文件。之后在interface builder中把collection view的類設(shè)置為HomeCollectionViewController。

然后:?

  • 在Storyboard中添加一個(gè)navigation controller
  • 把collection view設(shè)置為上面的navigation controller的root view controller。
  • 把這個(gè)navigation controller設(shè)置為initial view controller。
  • 接下來再次回到collection view controller。這個(gè)

    進(jìn)一步了解UICollectionView

    如前文所述,UICollectionView和UITableView類似,都有datasource和delegate。這樣就可以設(shè)置datasource和設(shè)置一些用戶的交互,比如選中某一個(gè)cell的時(shí)候怎么處理。

    UICollectionViewFlowLayout有一個(gè)代理:UICollectionViewDelegateFlowLayout。通過這個(gè)代理可以設(shè)定布局的一些行為比如:cell的間隔,collection view的滾動方向等。

    下面就開始在我們的代碼中給UICollectionViewDataSource和UICollectionViewDelegateFlowLayout?兩個(gè)代理的方法做一個(gè)填空。UICollectionViewDelegate里的方法暫時(shí)還用不著,稍后會給這個(gè)代理做填空。

    實(shí)現(xiàn)UICollectionViewDataSource

    這里我們用微博開放API為例。從微博的開發(fā)API上獲取到當(dāng)前用戶的全部的微博,然后用UICollectionView展示。獲取到的微博time line最后會放在這里:

    private var timeLineStatus: [StatusModel]?

    在data source中的代碼就很好添加了。

    // MARK: UICollectionViewDataSourceoverride func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {return 1 //1}override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {return self.timeLineStatus?.count ?? 0 //2}override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath)cell.backgroundColor = UIColor.orangeColor() //3return cell}
  • 我們只要一個(gè)section,所以這里返回?cái)?shù)字1。
  • 返回的time line都會放在類型為StatusModel的數(shù)組里。這個(gè)數(shù)組可能為空,因?yàn)楹芏嗲闆r會影響到網(wǎng)絡(luò)請求,比如網(wǎng)絡(luò)不通的時(shí)候。這個(gè)時(shí)候返回的time line就是空了。所以self.timeLineStatus?.count得出的數(shù)字也可能是空,那么這個(gè)時(shí)候就應(yīng)該返回0。
  • 由于沒有合適的Cell返回,現(xiàn)在只好用改變Cell的背景色的方式看到Cell的排布。
  • 效果是這樣的:?

    UICollectionViewFlowLayoutDelegate

    這個(gè)代理的作用和UITableView的func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat有非常類似的作用。heightForRowAtIndexPath的作用是返回UITableViewCell的高度。而UICollectionViewCell有非常多的不同的大小,所以需要更加復(fù)雜的代理方法的支持。其中包括兩個(gè)方法:

    // 1 class HomeCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout // 2 private let sectionInsets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0) // MARK: UICollectionViewDelegateFlowLayout// 3 func collectionView(collectionView: UICollectionView, layout collectionViewLayout:UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {return CGSize(width: 170, height: 300) }// 4 func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {return sectionInsets }
  • 首先需要實(shí)現(xiàn)layout的代理UICollectionViewDelegateFlowLayout。
  • 給類添加一個(gè)sectionInsets的屬性。
  • UICollectionViewDelegateFlowLayout的第一個(gè)方法,用來返回indexPath指定位置的Cell的Size。
  • layout代理的另外一個(gè)方法,用來返回每一個(gè)section的inset。
  • 看看運(yùn)行效果:?

    創(chuàng)建自定義UICollectionViewCell

    下面就要處理內(nèi)容在展示的時(shí)候具體應(yīng)該怎么展示了。我們這里分兩種情況,如果用戶的微博有圖片,那么就展示圖片。如果沒有圖片就展示文字。可惜的是微博的API沒有圖片的大小返回回來。展示的時(shí)候需要大小參數(shù)來決定這個(gè)?
    UICollectionViewCell到底要多大的size,由于沒有就只好弄個(gè)方塊來展示圖片了。至于圖片的拉伸方式就有你來決定了,我們這里為了簡單就使用默認(rèn)的方式拉伸圖片。

    在文字上就需要根據(jù)文字的多少了決定size了。由于我們的寬度是一定的,也就是說在autolayout中UILabel的preferredMaxLayoutWidth是一定的。然后就可以很方便的根據(jù)這個(gè)寬度來計(jì)算多行的UILabel到底需要多少的高度來全部展示微博中的文字。

    首先是展示圖片的Cell。?

    在Cell上放一個(gè)UIImageView,保證這個(gè)image view的四個(gè)邊距都是0。

    創(chuàng)建一個(gè)文件WeiboImageCell.swift,里面是類WeiboImageCell,繼承自UICollectionViewCell。?

    把這個(gè)Cell的custom class設(shè)置為WeiboImageCell。?
    ?
    然后把Cell代碼中的image view和interface builder的image view關(guān)聯(lián)為IBOutelt

    class WeiboImageCell: UICollectionViewCell {@IBOutlet weak var weiboImageView: UIImageView! }

    重復(fù)上面的步驟添加一個(gè)只有一個(gè)UILabel的Cell,類型為WeiboTextCell。設(shè)置這個(gè)UILabel的屬性numberOfLines為0,這樣就可以顯示多行的文字。然后設(shè)置這個(gè)label的上、左、下、右都是-8。

    為什么是-8呢,因?yàn)樘O果默認(rèn)的給父view留了寬度為8的margin(邊距),如果要文字和Cell的邊距貼合的話 需要覆蓋這個(gè)系統(tǒng)預(yù)留的邊距,因此需要設(shè)置邊距為-8。

    最后關(guān)聯(lián)代碼和label。

    class WeiboTextCell: UICollectionViewCell {@IBOutlet weak var weiboTextLabel: UILabel! }

    添加完這兩個(gè)Cell之后,回到HomeCollectionViewController。刪除self.collectionView!.registerClass(WeiboImageCell.self, forCellWithReuseIdentifier: reuseIdentifier)方法,以及全部的registerClass。

    `registerClass`, 這個(gè)方法的調(diào)用會把我們在storyboard里做的一切都給抹掉。在調(diào)用Cell里的image view或者label的時(shí)候得到的永遠(yuǎn)是nil。

    到這,我們需要討論一下text cell對于label的約束問題。首先我們同樣設(shè)置label的約束,讓這個(gè)label貼著cell的邊。也就是,top、leading、trailing和bottom為-8。

    但是這樣的而設(shè)置讓label在顯示出來的cell中是居中的。尤其在文字不足夠現(xiàn)實(shí)滿cell的空間的時(shí)候。所以,我們需要改一個(gè)地方。修改bottom的優(yōu)先級,設(shè)置為low,最低:UILayoutPriorityDefaultLow。這樣在labe計(jì)算高度的時(shí)候會優(yōu)先考慮的是文字填滿label后的高度,而不是像之前一樣直接把labe的高度設(shè)置為cell的高度。這個(gè)時(shí)候不論文字是否填滿cell,都是從頂開始顯示有多少控件用多少空間。

    集成SDWebImage

    我們那什么來拯救圖片cell惹?辣就是SDWebImage是一個(gè)著名的圖片請求和緩存的庫。我們這里用這個(gè)庫來請求微博中的圖片并緩存。

    添加:?
    Podfile里添加SDWebImage的pod應(yīng)用pod ‘SDWebImage’, ‘~>3.7’。當(dāng)然了之前我們已經(jīng)添加了user_frameworks!。為什么用這個(gè)看原文:

    You can make CocoaPods integrate to your project via frameworksinstead of static libraries by specifying use_frameworks!.

    多了就不多說了,需要了解更多的可以看這里。

    pod更新完成之后。引入這個(gè)framework。

    import SDWebImage

    然后就可以給cell的image view上圖片了。

    weiboImageCell.weiboImageView.sd_setImageWithURL(NSURL(string: status.status?.bmiddlePic ?? ""))

    SDWebImage給image view寫了一個(gè)category。里面有很多可以調(diào)用的方法。比如可以設(shè)置一個(gè)place holder的image。也就是在image沒有下載下來之前可以給image view設(shè)置一個(gè)默認(rèn)的圖片。

    http請求和數(shù)據(jù)

    這里只是簡單說一下,更過的內(nèi)容請看這里。?
    下面我們看看微博的Open API能給我們返回什么:

    {"statuses": [{"created_at": "Tue May 31 17:46:55 +0800 2011","id": 11488058246,"text": "求關(guān)注。","source": "<a href="http://weibo.com" rel="nofollow">新浪微博</a>","favorited": false,"truncated": false,"in_reply_to_status_id": "","in_reply_to_user_id": "","in_reply_to_screen_name": "","geo": null,"mid": "5612814510546515491","reposts_count": 8,"comments_count": 9,"annotations": [],"user": {"id": 1404376560,"screen_name": "zaku","name": "zaku","province": "11","city": "5","location": "北京 朝陽區(qū)","description": "人生五十年,乃如夢如幻;有生斯有死,壯士復(fù)何憾。","url": "http://blog.sina.com.cn/zaku","profile_image_url": "http://tp1.sinaimg.cn/1404376560/50/0/1","domain": "zaku","gender": "m","followers_count": 1204,...}},...],"ad": [{"id": 3366614911586452,"mark": "AB21321XDFJJK"},...],"previous_cursor": 0, // 暫時(shí)不支持"next_cursor": 11488013766, // 暫時(shí)不支持"total_number": 81655 }

    我們只需要我們follow的好友的微博的圖片或者文字。所以由這些內(nèi)容我們可以定義出對應(yīng)的model類。

    import ObjectMapperclass BaseModel: Mappable {var previousCursor: Int?var nextCursor: Int?var hasVisible: Bool?var statuses: [StatusModel]?var totalNumber: Int?required init?(_ map: Map) {}func mapping(map: Map) {previousCursor <- map["previous_cursor"]nextCursor <- map["next_cursor"]hasVisible <- map["hasvisible"]statuses <- map["statuses"]totalNumber <- map["total_number"]} }

    import ObjectMapperclass StatusModel: BaseModel {var statusId: String?var thumbnailPic: String?var bmiddlePic: String?var originalPic: String?var weiboText: String?var user: WBUserModel?required init?(_ map: Map) {super.init(map)}override func mapping(map: Map) {super.mapping(map)statusId <- map["id"]thumbnailPic <- map["thumbnail_pic"]bmiddlePic <- map["bmiddle_pic"]originalPic <- map["original_pic"]weiboText <- map["text"]} }

    其中內(nèi)容全部都放在類StatusModel中,圖片我們用屬性bmiddlePic,文字用weiboText。其他屬性留著以后使用。

    請求完成以后,這些time line的微博會存在一個(gè)屬性里做為數(shù)據(jù)源使用。

    class HomeCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {private var timeLineStatus: [StatusModel]? // 1//2Alamofire.request(.GET, "https://api.weibo.com/2/statuses/friends_timeline.json", parameters: parameters, encoding: .URL, headers: nil).responseString(completionHandler: {response inlet statuses = Mapper<BaseModel>().map(response.result.value)if let timeLine = statuses where timeLine.totalNumber > 0 {self.timeLineStatus = timeLine.statuses // 3self.collectionView?.reloadData()}}) }
  • 存放數(shù)據(jù)源的屬性。
  • Alamofire發(fā)出http請求。
  • 請求成功之后解析數(shù)據(jù),并把我們需要的微博數(shù)據(jù)存放在屬性self.timeLineStatus。
  • 在展示數(shù)據(jù)的時(shí)候需要區(qū)分微博的圖片是否存在,存在則優(yōu)先展示圖片,否則展示文字。

    一個(gè)不怎么好的做法是在方法cell for collection view里判斷數(shù)據(jù)源是否存在,遍歷每一個(gè)數(shù)據(jù)源的item判斷這個(gè)item是否有圖片。。。

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {if let statuses = self.timeLineStatus {let status = statuses[indexPath.item]if status } }

    這樣顯然太過冗長了,所以我們要把這一部分代碼提升出來。

    /**get status and if this status has image or not@return:status, one of the timelineInt, 1: there's image, 0: there's no image, -1: empty status*/func getWeiboStatus(indexPath: NSIndexPath) -> (status: StatusModel?, hasImage: Int) { // 1if let timeLineStatusList = self.timeLineStatus where timeLineStatusList.count > 0 {let status = timeLineStatusList[indexPath.item]if let middlePic = status.bmiddlePic where middlePic != "" {// there's middle sized image to showreturn (status, 1)} else {// start to consider textreturn (status, 0)}}return (nil, -1)}

    swift是可以在一個(gè)方法里返回多個(gè)值的。這個(gè)多個(gè)內(nèi)容的值用tuple來存放。調(diào)用時(shí)這樣的:

    let status = self.getWeiboStatus(indexPath) let hasImage = status?.hasImage // if there's a image let imageUrl = status.status?.bmiddlePic // image path let text = status.status?.weiboText // text

    只要通過let hasImage = status?.hasImage就可以判斷是否有圖片。所以Swift的這一點(diǎn)還是非常方便的。那么在判斷要顯示哪一種Cell的時(shí)候就非常的方便了。修改后的代碼也非常的簡潔。這個(gè)習(xí)慣需要一直保持下去。

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {let status = self.getWeiboStatus(indexPath)var cell: UICollectionViewCell = UICollectionViewCell()guard let _ = status.status else {cell.backgroundColor = UIColor.darkTextColor()return cell}if status.hasImage == 1 {cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath)let weiboImageCell = cell as! WeiboImageCellweiboImageCell.weiboImageView.backgroundColor = UIColor.blueColor()weiboImageCell.weiboImageView.sd_setImageWithURL(NSURL(string: status.status?.bmiddlePic ?? ""))} else if status.hasImage == 0 {cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseTextIdentifier, forIndexPath: indexPath)let weiboTextCell = cell as! WeiboTextCellweiboTextCell.setCellWidth(self.cellWidth)weiboTextCell.weiboTextLabel.text = status.status?.weiboText ?? ""weiboTextCell.contentView.backgroundColor = UIColor.orangeColor()weiboTextCell.weiboTextLabel.backgroundColor = UIColor.redColor()} else {cell = UICollectionViewCell()}cell.backgroundColor = UIColor.orangeColor() //3return cell}

    跑起來,看看運(yùn)行效果。?

    好丑!!!

    ?

    全部代碼在這里。

    to be continued

    總結(jié)

    以上是生活随笔為你收集整理的Swift:用UICollectionView整一个瀑布流的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 亚洲国产一二三区 | 免费在线观看成人 | 欧美成人免费在线观看视频 | 99精品人妻无码专区在线视频区 | 一区二区成人精品 | 欧美一级免费视频 | 中国一级特黄毛片 | 亚洲精品大片www | 国产精品视频第一页 | 韩国精品在线观看 | 人妻无码一区二区三区四区 | 欧美日韩亚洲色图 | 刘亦菲国产毛片bd | 国产精品1区2区3区4区 | 一级片日韩 | xxxx国产| 国产素人在线观看 | 毛片在线视频观看 | 天天干夜夜看 | 国产一线天粉嫩馒头极品av | 伊人色综合久久久 | 日本成人片在线 | 欧美熟妇一区二区 | 高清国产一区二区三区 | 欧美视频第二页 | 国产福利91精品 | 裸体女人a级一片 | 日本免费在线视频观看 | 中国av在线播放 | 97在线免费视频观看 | 久久免费看少妇高潮 | 国产成人av影院 | 亚洲性xxx | 天天插天天 | 日韩欧美中文字幕一区二区三区 | 人妻熟妇又伦精品视频a | 狠狠干2021 | 成人福利免费视频 | 极品国产一区 | 国产手机看片 | 国产小视频在线观看免费 | 91久久国产视频 | 91蜜桃 | 国产日韩一区二区在线 | 用力抵着尿进去了h | 色眯眯av| 国产91精品看黄网站在线观看 | 亚洲综合色av | 少妇第一次交换又紧又爽 | 色哟哟中文字幕 | 久久精品视频网站 | 天天想你免费观看完整版高清电影 | 日少妇b| 欧美a久久 | 日韩电影一区 | 婷婷激情小说网 | 国产美女一区二区三区 | 亚洲av色香蕉一区二区三区 | 黄色在线播放 | 日韩国产网站 | 麻豆91在线播放 | 一级黄色aa | 国产v在线 | 精品国产综合区久久久久久 | 久久精品视频在线播放 | 国产在线精品一区二区 | 久久精品伊人 | 国产sss| 美国三级视频 | 亚洲成人黄色小说 | 色屁屁一区二区三区视频 | 国产伦精品一区二区. | 在线亚洲网站 | 最新黄色av | 色婷婷av一区 | 久色伊人 | 97人妻天天摸天天爽天天 | 亚洲无码一区二区三区 | 国产精品毛片va一区二区三区 | 欧美日韩日本国产 | 91伦理| 亚洲av永久纯肉无码精品动漫 | 中文字幕在线资源 | 福利一区二区在线观看 | 丝袜综合网 | 淫欲av | 一本无码aⅴ久久久国产 | www.亚色| 一区二区三区四区五区在线视频 | 性猛╳xxx乱大交 | 中文久久乱码一区二区 | 女性高潮视频 | 亚洲欧美国产视频 | 精品人妻在线播放 | 国产自产在线视频 | 国产精品毛片一区二区在线看 | 天天操人人 | 色呦呦在线免费观看 | 永久黄网站色视频免费观看w |