起因
今天给室友做ios作业时遇到的问题。
之前在慕课网看了些视频,swift基本语法和实战,大致了解了,敲了几百行代码热手。
我想按照视频看到的,利用Picker View实现一个简单的看图片的程序,再用上Navigation Controllor,考虑到室友喜欢曼城队,图片主角就选曼城的球员了,本来想用上Tab Bar Controllor,分为前中后场和门将四个分类显示球员。用到Picker View控件的时候想到了可以在Picker View里显示两个数据列,左边显示前中后场分类,右边显示对应的球员。
于是就遇到了问题:左边的选项改变,右边的选项不会更新。
下面的图是最终我想要得到的效果
探索
我首先想到的是修改下面这个接口,第一个函数的返回值表示Picker View控件有几列,用component表示,因为有两列,所以返回2。第二个函数返回每一列有几项,第一列的数目是固定的,问题在第二列的个数,需要根据第一列的值来确定,我一开始想根据不同的行row值来确定选了第一列的哪项,但是第二个函数里没有row这个参数。(下面两段代码都是最终的正确代码)
extension ViewController: UIPickerViewDataSource {
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 2
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == 0 {
return player_location.count
} else {
return show_players.count
}
}
}
我之所以想到用row值,是因为第二个接口里有一个不能省略的函数有row这个参数
extension ViewController: UIPickerViewDelegate {
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
if component == 0 {
return player_location[row]
} else {
/*if player.selectedRowInComponent(0) == 0 {
return fw_players[row]
} else if player.selectedRowInComponent(0) == 1 {
return mf_players[row]
} else {
return wb_players[row]
}*/
return show_players[row]
}
}
}
其中第一个pickerView函数是不能省略的,似乎是在OC里就有的接口。返回了每一列要绑定的数据。在这里的row是当前这一列选中的行,从0开始,所以在数组中可以直接作为下标。我就是想根据第一列的row值来改变第二列显示的内容。既然没有,我就尝试把UIPickerViewDataSource接口pickerView函数第二列的返回值设为一个很大的值,大于所有分类下的数组大小。可惜不行,返回的个数必须与数组的大小严格一致,否则运行会崩溃。
我去除了门将分类,把剩下三个分类下数组的大小都调整为5,这样UIPickerViewDataSource接口的pickerView函数关于第二列的返回值就可以固定为5,解决了返回值问题。然后在UIPickerViewDelegate接口的pickView函数里根据第一列的值返回不同的数组(前中后场三个数组)。但运行时,改变了第一列的值,第二列还是不变,显然这个方法不是在值改变时调用的。
上面代码中的player就是这个Picker View实例化的对象。我在它的方法中翻了翻,发现了selectedRowInComponent()这个函数,参数传第几列,它返回这一列的第几行被选中。我猜测它应该和row参数的效果一样,我改成如上面代码注释部分所写,运行发现它和row参数的效果不一样,并且它真的使第二列的内容发生了改变!但是这个改变很隐晦,需要把第二列滑动,然后因滑动而看不见的部分才会改变,并且不管这个分类下数组的大小是几,最终都显示和第一个分类的数组大小一样数目的内容,因为初始时第一列的第一个值被选中。此时我的第一个分类数组大小是4,第二个和第三个大小都是6,我觉得如果第二个或第三个大小比第一个小的话运行也会崩溃,不过我没尝试。显然,这不是解决方案。
解决
先百度答案,发现全是OC的方法,没有swift的方法,再google,搜索结果和百度差不多。本来想在stackoverflow上面提问,觉得编英语我会十分痛苦,就在segmentfault上提问了,然后继续看OC的解决方法希望找到灵感,虽然语法不同,但都继承了两个相同的接口,并且OC里多了几个函数。我试了试,发现UIPickerViewDelegate这个接口里pickerView函数有一个重载和OC里的那个参数一样,试着写了一下,因为不可省的pickView里不能按照先前的方法return,所以又定义了一个显示数组,在重载的pickView里用来更新这个数组。最后调用reloadComponent(1)方法,表示刷新Picker View控件的第二列,运行发现成功了。重载函数代码如下,这个函数才是Picker View控件选项值改变时调用的函数
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if component == 0 {
if player.selectedRowInComponent(0) == 0 {
show_players = fw_players
} else if player.selectedRowInComponent(0) == 1 {
show_players = mf_players
} else if player.selectedRowInComponent(0) == 2 {
show_players = wb_players
} else {
show_players = gk_players
}
player.reloadComponent(1)
}
}
这是曼城的球迷啊
楼主这个blog咋搭建的。写一个搭建这个blog的文章吧。。。