每个分段表行的附件视图中的 UISwitch

Posted

技术标签:

【中文标题】每个分段表行的附件视图中的 UISwitch【英文标题】:UISwitch in each sectioned table row's accessoryView 【发布时间】:2013-07-19 14:04:48 【问题描述】:

我是 ios 编码的新手,我在 SO 中环顾四周并尝试了几种方法来解决这个问题,但似乎没有任何效果。我确信这是因为我的一些愚蠢的错误:-)

我有一个分区表,总共大约 25 行,分为 2 个部分。 每个cell.accessoryView 都有一个开关,我尝试在开关状态更改时将其存储在NSArray 中,但是在该索引处记录数组内容在任何情况下都会奇怪地返回0。 (数组被实例化为TableViewController的属性(nonatomic, readwrite),并合成)

显然,当我上下滚动表格时,所有开关都返回默认的OFF 状态。

感谢您的帮助!

- (void)viewDidLoad

[super viewDidLoad];
//countries dict and switch state array init..  
self.countries = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"countries" ofType:@"plist"]];
NSNumber *b = [NSNumber numberWithBool:NO];
for (int i=0; i<210; i++) 
    [statiSwitch addObject:b];
    NSLog(@"%d", [[statiSwitch objectAtIndex:i] integerValue]);


//tableview drawing..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

static NSString *CellIdentifier = @"CellWithSwitch";    
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) 
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];


NSString *continent = [self tableView:tableView titleForHeaderInSection:indexPath.section];
NSString *country = [[self.countries valueForKey:continent] objectAtIndex:indexPath.row];

//Simple tag calculation...
NSInteger tagOb = indexPath.section * 100 + indexPath.row;

UISwitch *mySwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
[mySwitch addTarget:self action:@selector(switchChange:) forControlEvents:UIControlEventValueChanged];
mySwitch.tag = tagOb;
if ([statiSwitch count] > tagOb) 
    [mySwitch setOn:[[statiSwitch objectAtIndex:tagOb] boolValue] animated:NO];
     

cell.textLabel.text = country;    
cell.accessoryView = mySwitch;

return cell;

然后是切换状态变化时调用的方法:

- (void) switchChange:(UISwitch *)sender 
NSNumber *c = [NSNumber numberWithBool:sender.on];
[statiSwitch replaceObjectAtIndex:sender.tag withObject:c];

NSLog(@"switch tag is: %i and state is: %d", sender.tag, sender.on);
NSLog(@"switch states array value: %d", [[statiSwitch objectAtIndex:sender.tag] integerValue]);

【问题讨论】:

尝试子类化 UITableViewCell,并将整个单元格存储在一个数组中,而不仅仅是开关值。然后,随着 tableView 滚动,将单元格拉出数组而不是出队。 那么,我应该设置一个包含所有(比方说)20 个单元对象的数组,包括附件开关,然后让- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 方法从该数组中取出单元?跨度> 你应该继承 UITableViewCell,并在该类中处理切换操作。这就像使用对象类来存储数据一样。 好的,我试试看!谢谢! (如果您建议我为处理开关操作的子类提供一些示例代码.. 那会很棒:-) 您是在做故事板,还是全部用代码完成?使用故事板,这是一个非常简单的过程。 【参考方案1】:

我认为您在向其添加对象之前忽略了初始化 statiSwitch。

在for循环前的viewDidLoad中,添加这一行

statiSwitch = [NSMutableArray array];

【讨论】:

我将继续使用 int 数组。但你是对的@Rick,我忘了在上面的代码中初始化数组:statiSwitch 被声明为 @987654323 的属性@,合成等等,这就是为什么我认为没有必要再次分配和初始化它。 别担心,记住这一点。在很多情况下你仍然需要使用 NSMutableArrays。如果你想学习 iOS 编程,你不能总是坚持使用 C。干杯。【参考方案2】:
    设置自定义单元类。 在情节提要中创建一个原型单元,并在其中放置一个开关。 将原型单元设置为您的自定义类,并设置重用标识符。 将开关连接到自定义单元类中的 IBOutlet。 (如果您希望您的单元能够通信,还可以设置 @protocol 和委托) 现在是棘手/骇人听闻的部分:

在 -viewDidLoad 中:

    for (int i = 0; i < [self.cellDataArray count]; ++i) 
            CustomCell *cell;

    cell = [self.tableView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:nil];
    cell.delegate = self;
    [self.cellsArray addObject:cell];

    在您的 cellForRowAtIndexPath 中,执行以下操作:

    cell = self.cellsArray[indexPath.row]; // 如果使用 collectionView,则为 .item

    由于开关连接到每个单元,因此您需要在 CustomCell 类中提供一个方法,该方法将基于开关执行某些操作,并且可能会向委托类发送调用。

【讨论】:

非常感谢!我会尽力让你知道。 我尝试过这种方式,单元格数组和其他部分都很好,但是我在 cell = [self.tableView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:nil]; 行中收到了编译器警告,将其放在 -viewDidLoad: 方法中。它告诉我tableView 没有dequeueReusableCellWithReuseIdentifier: 的任何标识符。我用一个解决方法解决了这个问题,使用一个简单的 int 数组来存储开关值。不知道它不能在 NSObjects 的 NSMutableArray 中存储值。有关详细信息,请参阅我的答案。 如果您将@"Cell" 更改为@"CellWithSwitch",您就不会遇到这个问题。 在我的回答中我写了“@Cella”而不是“@CellWithSwitch”,因为那是我在情节提要和编辑的“表格视图控制器”.m 文件中使用的新标识符【参考方案3】:

我使用了一个简单的int array 来存储开关值,它似乎比由具有switchTag 和switchState 属性的对象组成的NSMutableArray 工作得更好,这是我以前做的。

代码如下:

- (void)viewDidLoad
   
    //[here goes the code to retrieve my table data from a dictionary, getting sections and rows]

    //int array iniazialization, with zeros to have switches set at OFF at beginning

    for (int i = 0; i < 300; i++) 
    switchStates[i] = 0;
        


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath


    static NSString *CellIdentifier = @"Cella"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) 
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];


//Cell drawing..

NSString *continent = [self tableView:tableView titleForHeaderInSection:indexPath.section];
NSString *country = [[self.countries valueForKey:continent] objectAtIndex:indexPath.row];
cell.textLabel.text = country;

//Calculate the tag to be assigned to the switches..

    switchTag = indexPath.section * 100 + indexPath.row
    UISwitch *mySwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
    [mySwitch addTarget:self action:@selector(switchChange:) forControlEvents:UIControlEventValueChanged];
    mySwitch.tag = switchTag;
    mySwitch.on = switchStates[switchTag];

    cell.accessoryView = mySwitch;

    return cell;



//switch change action..

- (void) switchChange:(UISwitch *)sender 
     switchStates[sender.tag] = sender.on;

现在我“只是”将这些开关值存储在核心数据中。在我即将提出的问题中见 :-)

【讨论】:

以上是关于每个分段表行的附件视图中的 UISwitch的主要内容,如果未能解决你的问题,请参考以下文章

如何使用单个查询获取存储在不同变量中的多个表行的计数?

使用Angularjs的每个表行的重复表单

使用 jQuery 将类添加到每个表行的第一个 TD

在 OBIEE 中将总计添加到数据透视表行的末尾

iOS - 防止 UIAppearance 设置更改 UIWebView 输入附件视图

如何在分段控制器内的 tableView 中保存选定行的状态?