滚动 tableview 时 UISegment 值发生变化
UISegment value changing when tableview get scrolled
我正在使用 UISegmentControl 在 table 视图中显示 objective 类型的问题。但是,如果我 select 任何一个单元格中的一个段,那么如果我滚动,一些段值会改变。我不知道如何解决。
请指导我。
单元格大小: 160px
段色调:蓝色
编码
//UIViewController
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = segTblVw.dequeueReusableCellWithIdentifier("segment", forIndexPath: indexPath) as! segmentTblCell
return cell
}
//UITableViewCell CLASS
class segmentTblCell: UITableViewCell {
@IBOutlet weak var segMent: UISegmentedControl!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
下面的屏幕截图:
您遇到这个问题是因为 dequeueReusableCellWithIdentifier:
的工作原理。每次一个单元格滚出屏幕时,它都会进入一个缓存区域,在那里它会被重复使用。
假设您有 100 个单元格。他们所有的 segmentedControl
对象都设置为 first
。你点击一个来改变它的价值。当单元格移出视图时,它会进入缓存,如果您进一步向下滚动,它将在缓存中出队。
理解这一点很重要,因为 segmentedControl
对象实际上并没有改变。由于出列行为,它看起来正在发生变化。
要解决这个问题,您需要实现一个数据源来存储 segmentedControl
对象的值,这样您就可以在每次单元格出列时正确地重新初始化它。
方法 1: 通过将所有单元格对象保存在一个数组中来防止单元格的重用性
var arraysCells : NSMutableArray = []//globally declare this
在viewDidLoad()
for num in yourQuestionArray//this loop is to create all cells at beginning
{
var nib:Array = NSBundle.mainBundle().loadNibNamed("SegmentTableViewCell", owner: self, options: nil)
var cell = nib[0] as? SegmentTableViewCell
arraysCells.addObject(cell!);
}
在tableViewDelegate中,
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return arraysCells.objectAtIndex(indexPath.row) as! UITableViewCell
}
您可以通过迭代 arraysCells
找到选定的细分值(答案)
NOTE: Method 1 will be slow, if you have big number of cells
方法 2: 照常重用单元格,但使用委托和数组保存状态(输入值)。
在自定义 UITableViewCell 中
@objc protocol SegmentTableViewCellDelegate {
func controller(controller: SegmentTableViewCell, selectedSegmentIndex:Int, indexPath : NSIndexPath)
}
class SegmentTableViewCell: UITableViewCell {
var delegate: AnyObject?
var indexPath : NSIndexPath?
@IBOutlet weak var segment: UISegmentedControl! //outlet of segmented Control
@IBAction func onSegmentValueChanged(sender: UISegmentedControl/*if the parameter type is AnyObject changed it as UISegmentedControl*/)//action for Segment
{
self.delegate?.controller(self, selectedSegmentIndex: sender.selectedSegmentIndex, indexPath: indexPath!)
}
在viewController
class MasterViewController: SegmentTableViewCellDelegate{
var selectedAnswerIndex : NSMutableArray = [] //globally declare this
var selectedSegmentsIndexPath : NSMutableArray = [] //globally declare this
func controller(controller: SegmentTableViewCell, selectedSegmentIndex:Int, indexPath : NSIndexPath)
{
if(selectedSegmentsIndexPath.containsObject(indexPath))
{
selectedAnswerIndex.removeObjectAtIndex(selectedSegmentsIndexPath.indexOfObject(indexPath))
selectedSegmentsIndexPath.removeObject(indexPath)
}
selectedAnswerIndex.addObject(selectedSegmentIndex)
selectedSegmentsIndexPath.addObject(indexPath)
}
在 cellForRowAtIndexPath(tableView 委托)中
if(selectedSegmentsIndexPath.containsObject(indexPath))
{
cell?.segment.selectedSegmentIndex = selectedAnswerIndex.objectAtIndex(selectedSegmentsIndexPath.indexOfObject(indexPath)) as! Int
}
cell?.delegate = self
cell?.indexPath = indexPath
你可以通过
得到结果
for index in selectedSegmentsIndexPath
{
var cellIndexPath = index as! NSIndexPath
var answer : Int = selectedAnswerIndex.objectAtIndex(selectedSegmentsIndexPath.indexOfObject(cellIndexPath)) as! Int
NSLog("You have enterd answer \(answer) for question number \(cellIndexPath.row)")
}
@KelvinLau 的完美
您可以使用 var segmentedTracker : [NSIndexPath:Int] = [:]
在 segmentedValueChanged 上设置 selectedIndex 的值即:segmentedTracker[indexPath] = valueOf the selected index
然后在 cellForRowAtIndexPath 中检查值 let selected = [segmentedTracker]
cell.yourSegmentedControlReference.selectedIndex = selected
请注意这是伪代码我不记得属性名称了。从这里你可以自己弄清楚
我认为在 UITableViewCell 中使用 UISegmentControl 可能是错误的。
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UISegmentedControl_Class/
我在iOS申请中从未见过那种。
问题是 UITableViewCell 被 dequeueReusableCellWithIdentifier 方法重用了。所以一些 UISegmentControl 值在滚动时会改变。
虽然这不是最佳解决方案,但您可以使用静态单元格。您需要做的是只切换静态单元格。如果是这样,你就不会编写 UITableViewCell 的代码。
2018 年:更新答案
在此
中找到我最简单的答案
============================================= ==========
2015 年
我用自己的方式测试过。我的编码如下。请指导我,这是正确的方法还是错误的方法?我的问题得到解决。此代码停止可重复使用的单元格。
我的编码如下:
//UIViewController
var globalCell = segmentTblCell() //CUSTOM UITableViewCell Class
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = segTblVw.dequeueReusableCellWithIdentifier("segment", forIndexPath: indexPath) as! segmentTblCell
globalCell = segTblVw.dequeueReusableCellWithIdentifier("segment", forIndexPath: indexPath) as! segmentTblCell //THIS LINE - STOPS REUSABLE TABLE.
return cell
}
我正在使用 UISegmentControl 在 table 视图中显示 objective 类型的问题。但是,如果我 select 任何一个单元格中的一个段,那么如果我滚动,一些段值会改变。我不知道如何解决。 请指导我。
单元格大小: 160px
段色调:蓝色
编码
//UIViewController
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = segTblVw.dequeueReusableCellWithIdentifier("segment", forIndexPath: indexPath) as! segmentTblCell
return cell
}
//UITableViewCell CLASS
class segmentTblCell: UITableViewCell {
@IBOutlet weak var segMent: UISegmentedControl!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
下面的屏幕截图:
您遇到这个问题是因为 dequeueReusableCellWithIdentifier:
的工作原理。每次一个单元格滚出屏幕时,它都会进入一个缓存区域,在那里它会被重复使用。
假设您有 100 个单元格。他们所有的 segmentedControl
对象都设置为 first
。你点击一个来改变它的价值。当单元格移出视图时,它会进入缓存,如果您进一步向下滚动,它将在缓存中出队。
理解这一点很重要,因为 segmentedControl
对象实际上并没有改变。由于出列行为,它看起来正在发生变化。
要解决这个问题,您需要实现一个数据源来存储 segmentedControl
对象的值,这样您就可以在每次单元格出列时正确地重新初始化它。
方法 1: 通过将所有单元格对象保存在一个数组中来防止单元格的重用性
var arraysCells : NSMutableArray = []//globally declare this
在viewDidLoad()
for num in yourQuestionArray//this loop is to create all cells at beginning
{
var nib:Array = NSBundle.mainBundle().loadNibNamed("SegmentTableViewCell", owner: self, options: nil)
var cell = nib[0] as? SegmentTableViewCell
arraysCells.addObject(cell!);
}
在tableViewDelegate中,
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return arraysCells.objectAtIndex(indexPath.row) as! UITableViewCell
}
您可以通过迭代 arraysCells
NOTE: Method 1 will be slow, if you have big number of cells
方法 2: 照常重用单元格,但使用委托和数组保存状态(输入值)。
在自定义 UITableViewCell 中
@objc protocol SegmentTableViewCellDelegate {
func controller(controller: SegmentTableViewCell, selectedSegmentIndex:Int, indexPath : NSIndexPath)
}
class SegmentTableViewCell: UITableViewCell {
var delegate: AnyObject?
var indexPath : NSIndexPath?
@IBOutlet weak var segment: UISegmentedControl! //outlet of segmented Control
@IBAction func onSegmentValueChanged(sender: UISegmentedControl/*if the parameter type is AnyObject changed it as UISegmentedControl*/)//action for Segment
{
self.delegate?.controller(self, selectedSegmentIndex: sender.selectedSegmentIndex, indexPath: indexPath!)
}
在viewController
class MasterViewController: SegmentTableViewCellDelegate{
var selectedAnswerIndex : NSMutableArray = [] //globally declare this
var selectedSegmentsIndexPath : NSMutableArray = [] //globally declare this
func controller(controller: SegmentTableViewCell, selectedSegmentIndex:Int, indexPath : NSIndexPath)
{
if(selectedSegmentsIndexPath.containsObject(indexPath))
{
selectedAnswerIndex.removeObjectAtIndex(selectedSegmentsIndexPath.indexOfObject(indexPath))
selectedSegmentsIndexPath.removeObject(indexPath)
}
selectedAnswerIndex.addObject(selectedSegmentIndex)
selectedSegmentsIndexPath.addObject(indexPath)
}
在 cellForRowAtIndexPath(tableView 委托)中
if(selectedSegmentsIndexPath.containsObject(indexPath))
{
cell?.segment.selectedSegmentIndex = selectedAnswerIndex.objectAtIndex(selectedSegmentsIndexPath.indexOfObject(indexPath)) as! Int
}
cell?.delegate = self
cell?.indexPath = indexPath
你可以通过
得到结果for index in selectedSegmentsIndexPath
{
var cellIndexPath = index as! NSIndexPath
var answer : Int = selectedAnswerIndex.objectAtIndex(selectedSegmentsIndexPath.indexOfObject(cellIndexPath)) as! Int
NSLog("You have enterd answer \(answer) for question number \(cellIndexPath.row)")
}
@KelvinLau 的完美
您可以使用 var segmentedTracker : [NSIndexPath:Int] = [:]
在 segmentedValueChanged 上设置 selectedIndex 的值即:segmentedTracker[indexPath] = valueOf the selected index
然后在 cellForRowAtIndexPath 中检查值 let selected = [segmentedTracker]
cell.yourSegmentedControlReference.selectedIndex = selected
请注意这是伪代码我不记得属性名称了。从这里你可以自己弄清楚
我认为在 UITableViewCell 中使用 UISegmentControl 可能是错误的。
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UISegmentedControl_Class/
我在iOS申请中从未见过那种。
问题是 UITableViewCell 被 dequeueReusableCellWithIdentifier 方法重用了。所以一些 UISegmentControl 值在滚动时会改变。
虽然这不是最佳解决方案,但您可以使用静态单元格。您需要做的是只切换静态单元格。如果是这样,你就不会编写 UITableViewCell 的代码。
2018 年:更新答案
在此
============================================= ==========
2015 年
我用自己的方式测试过。我的编码如下。请指导我,这是正确的方法还是错误的方法?我的问题得到解决。此代码停止可重复使用的单元格。
我的编码如下:
//UIViewController
var globalCell = segmentTblCell() //CUSTOM UITableViewCell Class
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = segTblVw.dequeueReusableCellWithIdentifier("segment", forIndexPath: indexPath) as! segmentTblCell
globalCell = segTblVw.dequeueReusableCellWithIdentifier("segment", forIndexPath: indexPath) as! segmentTblCell //THIS LINE - STOPS REUSABLE TABLE.
return cell
}