{"id":2051,"date":"2016-03-28T02:15:18","date_gmt":"2016-03-28T06:15:18","guid":{"rendered":"http:\/\/www.rexfeng.com\/blog\/?p=2051"},"modified":"2016-03-28T02:15:18","modified_gmt":"2016-03-28T06:15:18","slug":"dynamic-infinite-uipickerview-scrolling-example","status":"publish","type":"post","link":"https:\/\/www.rexfeng.com\/blog\/2016\/03\/dynamic-infinite-uipickerview-scrolling-example\/","title":{"rendered":"Dynamic Infinite UIPickerView Scrolling Example"},"content":{"rendered":"<p>In iOS, I&#8217;ve seen a lot of examples of creating a UIPickerView with a hardcoded\u00a0array of strings. This may be necessary if your data set is a list of strings (such as USA states). For numbers, there&#8217;s a much easier way to dynamically generate each row&#8217;s title.<\/p>\n<p>To start off with, here&#8217;s a simple, programmatic UIPickerView implementation that includes the numbers (as strings) 0 through 9:<\/p>\n<pre>import UIKit\r\n\r\nclass ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {\r\n\r\n    override func viewDidLoad() {\r\n        super.viewDidLoad()\r\n        \r\n        setupPicker()\r\n    }\r\n\r\n    var pickerView: UIPickerView = UIPickerView()\r\n    var pickerDataSource = [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"]\r\n    \r\n    func setupPicker() {\r\n        pickerView.dataSource = self\r\n        pickerView.delegate = self\r\n        \r\n        pickerView.frame = CGRectMake(0, 0, view.frame.width, 300)\r\n        view.addSubview(pickerView)\r\n    }\r\n    \r\n    func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -&gt; String? {\r\n        return pickerDataSource[row]\r\n    }\r\n    \r\n    \/\/ columns count\r\n    func numberOfComponentsInPickerView(pickerView: UIPickerView) -&gt; Int {\r\n        return 1\r\n    }\r\n    \r\n    \/\/ rows count\r\n    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -&gt; Int {\r\n        return pickerDataSource.count\r\n    }\r\n}\r\n\r\n<\/pre>\n<p>The key piece is the <em>pickerDataSource<\/em>\u00a0that gives us our data source. It is an array literal, and in a worst case\u00a0programming scenario, one can imagine a very, very long hardcoded array of looping &#8220;0&#8221; &#8211; &#8220;9&#8221;. A long hardcoded array works, but is not\u00a0optimal for many reasons.<\/p>\n<p>The code above looks like this in the simulator:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2055\" src=\"http:\/\/www.rexfeng.com\/blog\/wp-content\/uploads\/2016\/03\/manual_ss.png\" alt=\"manual_ss\" width=\"310\" height=\"218\" srcset=\"https:\/\/www.rexfeng.com\/blog\/wp-content\/uploads\/2016\/03\/manual_ss.png 310w, https:\/\/www.rexfeng.com\/blog\/wp-content\/uploads\/2016\/03\/manual_ss-150x105.png 150w, https:\/\/www.rexfeng.com\/blog\/wp-content\/uploads\/2016\/03\/manual_ss-300x211.png 300w\" sizes=\"auto, (max-width: 310px) 100vw, 310px\" \/><\/p>\n<p>We can improve and change\u00a0this in many ways. We are going to update the code to operate without using a hardcoded array literal. Also, the user has to scroll up (or down) for a very, very long time before they hit the end of the picker. When their scrolling stops, we will\u00a0move the position of the selected row back to the middle, so that when they scroll again, there is a long way to go before they get to the top (or bottom).<\/p>\n<pre>import UIKit\r\n\r\nclass ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {\r\n    \r\n    var pickerView: UIPickerView = UIPickerView()\r\n    let pickerDataSize = 100_000\r\n    \r\n    override func viewDidLoad() {\r\n        super.viewDidLoad()\r\n        \r\n        setupPicker()\r\n    }\r\n    \r\n    func setupPicker() {\r\n        pickerView.dataSource = self\r\n        pickerView.delegate = self\r\n        \r\n        pickerView.frame = CGRectMake(0, 0, view.frame.width, 300)\r\n        view.addSubview(pickerView)\r\n        \r\n        \/\/ set the picker to the middle of the long list\r\n        pickerView.selectRow(pickerDataSize\/2, inComponent: 0, animated: false)\r\n    }\r\n    \r\n    func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -&gt; String? {\r\n        return String(row % 10)\r\n    }\r\n    \r\n    func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {\r\n        \/\/ do something with the resulting selected row\r\n        \r\n        \/\/ reset the picker to the middle of the long list\r\n        let position = pickerDataSize\/2 + row\r\n        pickerView.selectRow(position, inComponent: 0, animated: false)\r\n    }\r\n    \r\n    \/\/ columns count\r\n    func numberOfComponentsInPickerView(pickerView: UIPickerView) -&gt; Int {\r\n        return 1\r\n    }\r\n    \r\n    \/\/ rows count\r\n    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -&gt; Int {\r\n        return pickerDataSize\r\n    }\r\n}\r\n<\/pre>\n<p>In this 2nd code snippet for our ViewController, we have created a large number,\u00a0<em>pickerDataSize<\/em>, that tells our device how many rows there are. The neat thing is that we don&#8217;t need to create an array of 100K items. When the UIPickerViewDelegate&#8217;s\u00a0<em>titleForRow<\/em> method is called, it uses the row to dynamically return a string for that given row. Progress!<\/p>\n<p>As a bonus, I went ahead and added a call to\u00a0<em>pickerView.selectRow<\/em> in the\u00a0<em>didSelectRow<\/em> function. When the user finishes selecting a row, this call will silently (animated: false) move the\u00a0selected row back to the middle of the rows. This will maintain the illusion of infinite scrolling. Success!<\/p>\n<p>Here we can see the updated, dynamic picker view:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.rexfeng.com\/blog\/wp-content\/uploads\/2016\/03\/dynamic_ss.png\" alt=\"dynamic_ss\" width=\"310\" height=\"186\" class=\"alignnone size-full wp-image-2058\" srcset=\"https:\/\/www.rexfeng.com\/blog\/wp-content\/uploads\/2016\/03\/dynamic_ss.png 310w, https:\/\/www.rexfeng.com\/blog\/wp-content\/uploads\/2016\/03\/dynamic_ss-150x90.png 150w, https:\/\/www.rexfeng.com\/blog\/wp-content\/uploads\/2016\/03\/dynamic_ss-300x180.png 300w\" sizes=\"auto, (max-width: 310px) 100vw, 310px\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In iOS, I&#8217;ve seen a lot of examples of creating a UIPickerView with a hardcoded\u00a0array of strings. This may be necessary if your data set is a list of strings (such as USA states). For numbers, there&#8217;s a much easier way to dynamically generate each row&#8217;s title. To start off with, here&#8217;s a simple, programmatic [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1029],"tags":[1274,1278,1275,966,1277,1276],"class_list":["post-2051","post","type-post","status-publish","format-standard","hentry","category-programming","tag-dynamic","tag-example","tag-infinite","tag-ios","tag-pickerview","tag-uipickerview"],"_links":{"self":[{"href":"https:\/\/www.rexfeng.com\/blog\/wp-json\/wp\/v2\/posts\/2051","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.rexfeng.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.rexfeng.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.rexfeng.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.rexfeng.com\/blog\/wp-json\/wp\/v2\/comments?post=2051"}],"version-history":[{"count":12,"href":"https:\/\/www.rexfeng.com\/blog\/wp-json\/wp\/v2\/posts\/2051\/revisions"}],"predecessor-version":[{"id":2065,"href":"https:\/\/www.rexfeng.com\/blog\/wp-json\/wp\/v2\/posts\/2051\/revisions\/2065"}],"wp:attachment":[{"href":"https:\/\/www.rexfeng.com\/blog\/wp-json\/wp\/v2\/media?parent=2051"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rexfeng.com\/blog\/wp-json\/wp\/v2\/categories?post=2051"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rexfeng.com\/blog\/wp-json\/wp\/v2\/tags?post=2051"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}