實現無限輪播
生活雜談
- 最近很多童鞋私信我,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,否則控件將不能顯示
- 部分代碼解釋
// MARK:- 定義RecommendCycleView類
class RecommendCycleView: UIView {
// MARK: 控件屬性
@IBOutlet weak var collectionView: UICollectionView!
@IBOutlet weak var pageControl: UIPageControl!
// MARK: 系統回調
override func awakeFromNib() {
super.awakeFromNib()
// 設置不自動拉伸
autoresizingMask = .None
// 註冊cell
collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: kCycleCellID)
}
override func layoutSubviews() {
super.layoutSubviews()
// 設置collectionView的佈局
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = collectionView.bounds.size
}
}
// MARK:- 通過Xib快速創建的類方法
extension RecommendCycleView {
class func recommendCycleView() -> RecommendCycleView {
return NSBundle.mainBundle().loadNibNamed("RecommendCycleView", owner: nil, options: nil).first as! RecommendCycleView
}
}
// MARK:- 實現UICollectionView的數據源&代理
extension RecommendCycleView : UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 6
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(kCycleCellID, forIndexPath: indexPath)
cell.backgroundColor = indexPath.item % 2 == 0 ? UIColor.redColor() : UIColor.blueColor()
return cell
}
}
extension RecommendCycleView : UICollectionViewDelegate {
}
private lazy var cycleView : RecommendCycleView = {
let cycleView = RecommendCycleView.recommendCycleView()
cycleView.frame = CGRect(x: 0, y: -kCycleViewH, width: kScreenW, height: kCycleViewH)
return cycleView
}()
// 添加cycleView
collectionView.addSubview(cycleView)
collectionView.contentInset = UIEdgeInsets(top: kCycleViewH, left: 0, bottom: 0, right: 0)
請求數據&展示數據
請求數據
參數名稱 |
參數說明 |
version |
當前版本號:2.300 |
- 在RecommendViewMode中發送網絡請求
- 根據接口發送請求
- 定義CycleModel模型
- 將請求到的數據轉成模型對象
- 模型定義
class CycleModel: NSObject {
/// 輪播標題
var title : String = ""
/// 輪播圖片
var pic_url : String = ""
/// 輪播對應主播信息
var anchor : AnchorModel?
/// 主播信息
var room : [String : NSObject]? {
didSet {
guard let room = room else { return }
anchor = AnchorModel(dict: room)
}
}
// MARK: 構造函數
init(dict : [String : NSObject]) {
super.init()
setValuesForKeysWithDictionary(dict)
}
override func setValue(value: AnyObject?, forUndefinedKey key: String) {}
}
func requestCycleData(finishedCallback : () -> ()) {
NetworkTools.requestData(.GET, URLString: "http://www.douyutv.com/api/v1/slide/6?version=2.300") { (result) in
// 1.將結果轉成字典
guard let resultDict = result as? [String : NSObject] else { return }
guard let dataArray = resultDict["data"] as? [[String : NSObject]] else { return }
// 2.將字典轉成模型對象
for dict in dataArray {
self.cycleModels.append(CycleModel(dict: dict))
}
finishedCallback()
}
}
展示數據
- 將數據傳遞給RecommendCycleView對象
- 刷新UICollectionView
- 設置UIPageControl的個數
- 自定義Cell,用於展示數據
- 通過xib直接描述Cell
- 根據模型展示數據
class CollectionCycleCell: UICollectionViewCell {
// MARK: 控件屬性
@IBOutlet weak var iconImageView: UIImageView!
@IBOutlet weak var titleLabel: UILabel!
// MARK: 定義模型屬性
var cycleModel : CycleModel? {
didSet {
titleLabel.text = cycleModel?.title
let iconURL = NSURL(string: cycleModel?.pic_url ?? "")!
iconImageView.kf_setImageWithURL(iconURL)
}
}
}
實現無限輪播功能
- 在返回Cell個數地方,返回無限個數
- 例如:(cycleModels?.count ?? 0) * 10000
- 原因:無論用戶怎麼滾動,滾動幾天可能才能滾完
- 另外:因爲Cell有循環利用,是不會常見那麼多Cell的。不會造成內存很大
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (cycleModels?.count ?? 0) * 10000
}
func scrollViewDidScroll(scrollView: UIScrollView) {
let offset = scrollView.contentOffset.x + scrollView.bounds.width * 0.5
pageControl.currentPage = Int(offset / scrollView.bounds.width) % (cycleModels?.count ?? 1)
}
-
讓用戶向前滾動也可以
- 默認滾動到60處,那麼用戶向前滾動也有內容
- 注意:不需要太多,因爲用戶習慣來講是很少向前滾動的
let indexPath = NSIndexPath(forItem: (cycleModels?.count ?? 0) * 10, inSection: 0)
collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Left, animated: false)
-
自動滾動功能
// MARK:- 對定時器操作方法
extension RecommendCycleView {
private func addCycleTimer() {
cycleTimer = NSTimer(timeInterval: 3, target: self, selector: #selector(self.scrollToNext), userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(cycleTimer!, forMode: NSRunLoopCommonModes)
}
private func removeCycleTimer() {
cycleTimer?.invalidate()
cycleTimer = nil
}
@objc private func scrollToNext() {
// 滾動collectionView
let currentOffSet = collectionView.contentOffset.x + collectionView.bounds.width
collectionView.setContentOffset(CGPoint(x: currentOffSet, y: 0), animated: true)
}
}
- 監聽用戶拖拽
- 用戶拖拽過程中,定時器不更新
- 監聽用戶拖拽&結束拖拽即可
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
removeCycleTimer()
}
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
addCycleTimer()
}