小碼哥-玩轉【鬥魚直播APP】系列之實現無限輪播

實現無限輪播

生活雜談

  • 最近很多童鞋私信我,Swift項目有些語法跟不上。希望我出OC版的(OC版我會在後續推出),但是以我的考慮來說,Swift在語言排行版上面其實已經超過OC,另外國內現在新項目一般都會用Swift開發了。所有其實不能總是對於Swift是一種拒絕的態度,待在舒適區是會被淘汰的噢
  • 但是對於剛從OC轉Swift的人來說,確實Swift語法和OC差異太大,又沒有比較好的教程。後續我會看看能不能出一個OC快速轉向Swift的教程,不需要的童鞋可以先研究我們的項目,需要的童鞋可以抓緊時間學習一下

實現效果

  • 輪播效果

思路分析

  • 實現無限輪播常用的方案有三個:
    • 第三方框架:(不推薦,該功能並不難,而且三方框架中會有很多冗餘代碼)
    • UIScrollView:上面放三個View,自己實現三個View的循環利用
    • UICollectionView:利用系統會對UICollectionViewCell的循環利用機制實現
  • 方案選擇:
    • 方案三:簡單好用,循環利用的問題交給系統自己處理即可

界面搭建

  • 自定義一個UIView
    • 由於該View上面內容比較固定,因此可以直接通過Xib進行描述
    • 添加UICollectionView,佔據整個View,右下角添加UIPageControl
    • 設置UICollectionView的佈局,設置數據源以及實現數據源方法(見代碼)
    • 切記:設置自定義View的autoresizingMask = .None,否則控件將不能顯示
    • 部分代碼解釋
  1. // MARK:- 定義RecommendCycleView類
  2. class RecommendCycleView: UIView {
  3. // MARK: 控件屬性
  4. @IBOutlet weak var collectionView: UICollectionView!
  5. @IBOutlet weak var pageControl: UIPageControl!
  6. // MARK: 系統回調
  7. override func awakeFromNib() {
  8. super.awakeFromNib()
  9. // 設置不自動拉伸
  10. autoresizingMask = .None
  11. // 註冊cell
  12. collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: kCycleCellID)
  13. }
  14. override func layoutSubviews() {
  15. super.layoutSubviews()
  16. // 設置collectionView的佈局
  17. let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
  18. layout.itemSize = collectionView.bounds.size
  19. }
  20. }
  21. // MARK:- 通過Xib快速創建的類方法
  22. extension RecommendCycleView {
  23. class func recommendCycleView() -> RecommendCycleView {
  24. return NSBundle.mainBundle().loadNibNamed("RecommendCycleView", owner: nil, options: nil).first as! RecommendCycleView
  25. }
  26. }
  27. // MARK:- 實現UICollectionView的數據源&代理
  28. extension RecommendCycleView : UICollectionViewDataSource {
  29. func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  30. return 6
  31. }
  32. func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
  33. let cell = collectionView.dequeueReusableCellWithReuseIdentifier(kCycleCellID, forIndexPath: indexPath)
  34. cell.backgroundColor = indexPath.item % 2 == 0 ? UIColor.redColor() : UIColor.blueColor()
  35. return cell
  36. }
  37. }
  38. extension RecommendCycleView : UICollectionViewDelegate {
  39. }
  • 將自定義View添加到UICollectionView中

    • 懶加載RecommendCycleView對象
    • 將cycleView添加到UICollectionView中
    • 設置UICollectionView的內邊距
    • 代碼如下:
  • 懶加載RecommendCycleView

  1. private lazy var cycleView : RecommendCycleView = {
  2. let cycleView = RecommendCycleView.recommendCycleView()
  3. cycleView.frame = CGRect(x: 0, y: -kCycleViewH, width: kScreenW, height: kCycleViewH)
  4. return cycleView
  5. }()
  • 添加到collectionView中
  1. // 添加cycleView
  2. collectionView.addSubview(cycleView)
  3. collectionView.contentInset = UIEdgeInsets(top: kCycleViewH, left: 0, bottom: 0, right: 0)

請求數據&展示數據

請求數據

參數名稱 參數說明
version 當前版本號:2.300
  • 在RecommendViewMode中發送網絡請求
    • 根據接口發送請求
    • 定義CycleModel模型
    • 將請求到的數據轉成模型對象
  • 模型定義
  1. class CycleModel: NSObject {
  2. /// 輪播標題
  3. var title : String = ""
  4. /// 輪播圖片
  5. var pic_url : String = ""
  6. /// 輪播對應主播信息
  7. var anchor : AnchorModel?
  8. /// 主播信息
  9. var room : [String : NSObject]? {
  10. didSet {
  11. guard let room = room else { return }
  12. anchor = AnchorModel(dict: room)
  13. }
  14. }
  15. // MARK: 構造函數
  16. init(dict : [String : NSObject]) {
  17. super.init()
  18. setValuesForKeysWithDictionary(dict)
  19. }
  20. override func setValue(value: AnyObject?, forUndefinedKey key: String) {}
  21. }
  • 數據請求
  1. func requestCycleData(finishedCallback : () -> ()) {
  2. NetworkTools.requestData(.GET, URLString: "http://www.douyutv.com/api/v1/slide/6?version=2.300") { (result) in
  3. // 1.將結果轉成字典
  4. guard let resultDict = result as? [String : NSObject] else { return }
  5. guard let dataArray = resultDict["data"] as? [[String : NSObject]] else { return }
  6. // 2.將字典轉成模型對象
  7. for dict in dataArray {
  8. self.cycleModels.append(CycleModel(dict: dict))
  9. }
  10. finishedCallback()
  11. }
  12. }

展示數據

  • 將數據傳遞給RecommendCycleView對象
    • 刷新UICollectionView
    • 設置UIPageControl的個數
  • 自定義Cell,用於展示數據
    • 通過xib直接描述Cell
  • 根據模型展示數據
    • 代碼如下:
  1. class CollectionCycleCell: UICollectionViewCell {
  2. // MARK: 控件屬性
  3. @IBOutlet weak var iconImageView: UIImageView!
  4. @IBOutlet weak var titleLabel: UILabel!
  5. // MARK: 定義模型屬性
  6. var cycleModel : CycleModel? {
  7. didSet {
  8. titleLabel.text = cycleModel?.title
  9. let iconURL = NSURL(string: cycleModel?.pic_url ?? "")!
  10. iconImageView.kf_setImageWithURL(iconURL)
  11. }
  12. }
  13. }

實現無限輪播功能

  • 在返回Cell個數地方,返回無限個數
    • 例如:(cycleModels?.count ?? 0) * 10000
    • 原因:無論用戶怎麼滾動,滾動幾天可能才能滾完
    • 另外:因爲Cell有循環利用,是不會常見那麼多Cell的。不會造成內存很大
  1. func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  2. return (cycleModels?.count ?? 0) * 10000
  3. }
  • 隨着用戶的滾動,改變pageControl的顯示
    • 監聽UICollectionView的滾動即可
  1. func scrollViewDidScroll(scrollView: UIScrollView) {
  2. let offset = scrollView.contentOffset.x + scrollView.bounds.width * 0.5
  3. pageControl.currentPage = Int(offset / scrollView.bounds.width) % (cycleModels?.count ?? 1)
  4. }
  • 讓用戶向前滾動也可以

    • 默認滾動到60處,那麼用戶向前滾動也有內容
    • 注意:不需要太多,因爲用戶習慣來講是很少向前滾動的
      1. let indexPath = NSIndexPath(forItem: (cycleModels?.count ?? 0) * 10, inSection: 0)
      2. collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Left, animated: false)
  • 自動滾動功能

    • 添加定時器
    • 每隔3秒鐘自動滾動到下一個
  1. // MARK:- 對定時器操作方法
  2. extension RecommendCycleView {
  3. private func addCycleTimer() {
  4. cycleTimer = NSTimer(timeInterval: 3, target: self, selector: #selector(self.scrollToNext), userInfo: nil, repeats: true)
  5. NSRunLoop.mainRunLoop().addTimer(cycleTimer!, forMode: NSRunLoopCommonModes)
  6. }
  7. private func removeCycleTimer() {
  8. cycleTimer?.invalidate()
  9. cycleTimer = nil
  10. }
  11. @objc private func scrollToNext() {
  12. // 滾動collectionView
  13. let currentOffSet = collectionView.contentOffset.x + collectionView.bounds.width
  14. collectionView.setContentOffset(CGPoint(x: currentOffSet, y: 0), animated: true)
  15. }
  16. }
  • 監聽用戶拖拽
    • 用戶拖拽過程中,定時器不更新
    • 監聽用戶拖拽&結束拖拽即可
  1. func scrollViewWillBeginDragging(scrollView: UIScrollView) {
  2. removeCycleTimer()
  3. }
  4. func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
  5. addCycleTimer()
  6. }
來源:http://bbs.520it.com/forum.php?mod=viewthread&tid=2309
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章