Swift - UIPickerView无限循环滚动的实现(数据循环显示)
作者:hangge | 2017-12-11 08:10
UIPickerView 数据选择器在平时开发中经常会用到。当里面的数据项很多时,为了有更好的用户体验,许多应用的做法都是让它能循环滚动。也就是 pickerView 选项不管往上,还是往下都不会滚到底,数据会一直循环显示。下面演示如何实现这个功能。
一、单列 PickerView 的无限滚动
1,效果图
我们在 pickerView 里显示一月到十二月的数据。同时不管如何滚动,数据项总是会循环显示。
2,实现原理
(1)虽然 pickerView 没有自带这种循环滚动的功能,但我们可以把行数设成一个很大的值(比如本样例就设成 12 万)。然后让其在初始化时默认选择中间位置的项目。这样用户不管向上,还是向下基本上不能一次滚到底。
(2)同时我们在滚动停止后,还会自动将当前选中行移回到中间部分(当然动画要关闭,让用户察觉不到其实我们改变了选中行)。这样就会让用户保持无限滚动的幻觉。
3,样例代码
import UIKit class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource { //选择框 var pickerView: UIPickerView! //pickerView里的数据行数(12万) let pickerDataSize = 120_000 //pickerView显示的数据 let pickerData = ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"] override func viewDidLoad() { super.viewDidLoad() //初始化pickerView setupPickerView() } //初始化pickerView func setupPickerView() { pickerView = UIPickerView() pickerView.dataSource = self pickerView.delegate = self pickerView.frame = CGRect(x:0, y:64, width:view.frame.width, height:300) view.addSubview(pickerView) //让pickerView默认选中中间项 pickerView.selectRow(pickerDataSize/2, inComponent: 0, animated: false) } //设置pickerView的列数 func numberOfComponents(in pickerView: UIPickerView) -> Int { return 1 } //设置pickerView的行数 func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { return pickerDataSize } //设置pickerView各选项的内容 func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { return pickerData[row % pickerData.count] } //pickerView选中某一项后会触发 func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { //重新让pickerView又选回中间部分的数据项 let position = pickerDataSize / 2 + row % pickerData.count pickerView.selectRow(position, inComponent: 0, animated: false) } }
二、多列 PickerView 的无限滚动
1,效果图
- 我们这里使用 pickerView 实现一个省市联动选择器。第一列选择一个省后,第二列会显示该省下的所有市。
- 同时不管是第一列还是第二列,数据项都是可以循环滚动的。
2,实现原理
(1)这个实现原理同上面是一样的,同样是把每列的行数设置成一个特别大的值,然后初始时让其处于中间位置。
(2)由于有多列,每列的原始数据量是不同的。所以这里设定一个倍数(1 万),每列的行数都是:原始数据行数 * 倍数。
3,样例代码
import UIKit class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource { //选择框 var pickerView: UIPickerView! //pickerView里的原始数据的倍数(1万) let dataSizeMultiple = 10_000 //pickerView显示的数据 let provinceData = ["浙江", "江苏", "广东", "湖北"] let cityData = [["杭州", "丽水", "宁波", "舟山", "衡州", "嘉兴"], ["南京", "苏州", "无锡", "常州", "泰州"], ["广州", "珠海", "惠州", "清远"], ["武汉", "孝感", "恩施", "黄石", "荆州"],] //选择的省索引 var provinceIndex = 0 //选择的市索引 var cityIndex = 0 override func viewDidLoad() { super.viewDidLoad() //初始化pickerView setupPickerView() } //初始化pickerView func setupPickerView() { pickerView = UIPickerView() pickerView.dataSource = self pickerView.delegate = self pickerView.frame = CGRect(x:0, y:64, width:view.frame.width, height:200) view.addSubview(pickerView) //让pickerView默认选中中间项 pickerView.selectRow(dataSizeMultiple * provinceData.count/2, inComponent: 0, animated: false) pickerView.selectRow(dataSizeMultiple * cityData[0].count/2, inComponent: 1, animated: false) } //设置pickerView的列数 func numberOfComponents(in pickerView: UIPickerView) -> Int { return 2 } //设置pickerView的行数 func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { if component == 0 { return dataSizeMultiple * provinceData.count }else{ return dataSizeMultiple * cityData[component % provinceData.count].count } } //设置pickerView各选项的内容 func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { if component == 0 { return provinceData[row % provinceData.count] }else{ return cityData[provinceIndex][row % cityData[provinceIndex].count] } } //pickerView选中某一项后会触发 func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { //重新让pickerView又选回中间部分的数据项 if component == 0 { provinceIndex = row % provinceData.count let position = dataSizeMultiple * provinceData.count/2 + provinceIndex pickerView.selectRow(position, inComponent: 0, animated: false) //省改变后同步改变对应的市数据 cityIndex = 0 pickerView.reloadComponent(1) pickerView.selectRow(dataSizeMultiple * cityData[provinceIndex].count/2, inComponent: 1, animated: false) }else{ cityIndex = row % cityData[provinceIndex].count let position = dataSizeMultiple * cityData[provinceIndex].count/2 + cityIndex pickerView.selectRow(position, inComponent: 1, animated: false) } } //设置行高 func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { return 36 } }
全部评论(0)