您的位置:首页 > 移动开发

玩转【斗鱼直播APP】系列之实现无限轮播

2016-09-22 16:39 691 查看

实现无限轮播

生活杂谈

最近很多童鞋私信我,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 {



}


将自定义View添加到UICollectionView中

懒加载RecommendCycleView对象
将cycleView添加到UICollectionView中
设置UICollectionView的内边距
代码如下:

懒加载RecommendCycleView

private lazy var cycleView : RecommendCycleView = {

let cycleView = RecommendCycleView.recommendCycleView()

cycleView.frame = CGRect(x: 0, y: -kCycleViewH, width: kScreenW, height: kCycleViewH)

return cycleView

}()


添加到collectionView中
// 添加cycleView

collectionView.addSubview(cycleView)

collectionView.contentInset = UIEdgeInsets(top: kCycleViewH, left: 0, bottom: 0, right: 0)


请求数据&展示数据

请求数据

接口描述
接口名称:顶部轮播数据
接口地址:http://www.douyutv.com/api/v1/slide/6
请求参数:</br>

参数名称参数说明
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

}


随着用户的滚动,改变pageControl的显示
监听UICollectionView的滚动即可

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)


自动滚动功能

添加定时器
每隔3秒钟自动滚动到下一个

// 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()

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: