我正在努力找出在UITableView的标题中添加和管理UISwitch的最佳方法,到目前为止,我已经阅读了几个关于如何在表中最好地使用UISwitch的链接:这里、这里和这里。这些链接演示了在单元格中使用UISwitch,而我在标题的自定义UIView中使用它们。也就是说,我更喜欢使用标签来管理这些对象,但我不明白为什么viewWithTag方法不起作用。
附带说明:我可以在运行时将UISwitchers放入NSMutableArray中,并以这种方式进行管理,但我不想太冗长,不想管理数组上的边界冲突/索引,也不想检查零列表等。我也不清楚如何使用IBOutlets来做到这一点。这就是我尝试标签方法的原因。
我的目标是使用开关来折叠/展开每个部分中的行,这就是为什么我想将UISwitch标记为子视图并添加到我在viewForHeaderInSection中返回的UIView中。然后,当我需要执行一些逻辑来折叠单元格时,重新引用它们。此外,在运行时,我可能有一个或多个部分,因此对标签号进行硬编码是不切实际的。这是该方法的代码:
假设:
#define kSwitchTagRange 2000
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, 44)];
// Add UISwitches and ensure that UISwitch doesn't already exist for this section...
UISwitch *switchView = (UISwitch*)[self.tableView viewWithTag:(kLayerSwitchTagRange + section)];
if (switchView == nil) {
// Create switch
switchView = [[UISwitch alloc] init];
double xOffset = self.tableView.bounds.size.width - switchView.frame.size.width;
switchView.frame = CGRectMake(xOffset,
7,
switchView.frame.size.width,
switchView.frame.size.height);
[switchView addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
// Should we tag the switch view?
switchView.tag = kSwitchTagRange + section;
}
// Add switch as subview
[view addSubview:switchView];
return view;
}
在switchChanged:我只是重新加载表的数据:
- (void)switchChanged:(id)sender {
[self.tableView reloadData];
}
最后,当表的数据被重新创建时,我试图检索UISwitch并确定它的打开/关闭状态,然后如果关闭,我会为部分中的行数返回0,如果打开,我会返回一些其他数字:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger rowCount = 0;
UISwitch *switchView = (UISwitch*)[self.view viewWithTag:(kSwitchTagRange + section)];
if (switchView != nil && switchView.isOn == NO)
{
rowCount = 0;
}
else
{
// Row count is something other than 0
rowCount = 3;
}
return rowCount;
}
不幸的是,此switchView始终为零。
我有一些猜测,但无法确定为什么会发生这种情况。
- 猜测1:当表的数据被重新加载时,我想要的开关被添加到的UIView被释放。它不存在于内存中,因此无法通过标签搜索找到
- 猜测2:我错误地将UISwitch添加到视图对象中(在许多示例中,我看到对象添加到UITableViewCell的contentView中,但是由于我在viewForHeaderInSection:方法中发送回UIView,我不确定这些示例是否适用于此。addSubview应该将任何对象添加到树中
有人能告诉我为什么上面的viewWithTag方法会返回nil吗?我倾向于猜测#1,但没有找到任何文档告诉我自定义头UIView在任何时候都会被解除分配。单元格被重复使用,但是节头呢?
最后,我读过这篇文章,虽然关于标签使用的建议是有道理的,但我似乎根本不喜欢标签方法。如果你不觉得使用标签很麻烦,而且使用起来很智能,为什么不使用标签呢?为什么标签功能甚至可用?
真的,我只是想知道为什么在我的情况下viewWithTag方法返回nil。
干杯!
我不知道为什么你的viewWithTag总是返回nil,我确实认为这可能与视图在某个时候被释放有关。
但是,标记仍然可以执行您想要的操作,但您需要在模型对象中有一个跟踪开关值的属性或键。您可以使用标记来告知开关在其操作方法中的哪个部分,并适当地更新模型。以下是我所做的。我的模型是一个字典数组,其中键"rowData"的值是一个包含该部分所有数据的数组,键"switchValue"的值为NSNumber,0或1,表示交换机的状态。所以,我的数据看起来是这样的:
2012-11-28 22:50:03.104 TableWithSwitchesInHeaderView[3592:c07] (
{
rowData = (
One,
Two,
Three,
Four
);
switchValue = 1;
},
{
rowData = (
Red,
Orange,
Yellow,
Green,
Blue,
Violet
);
switchValue = 1;
},
)
这就是我在相关的表视图委托和数据源方法中所拥有的:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.theData.count;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, 44)];
UISwitch *switchView = [[UISwitch alloc] init];
double xOffset = self.tableView.bounds.size.width - switchView.frame.size.width;
switchView.frame = CGRectMake(xOffset,7,switchView.frame.size.width,switchView.frame.size.height);
[switchView addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
switchView.tag = kSwitchTagRange + section;
switchView.on = [[[self.theData objectAtIndex:switchView.tag - 101] valueForKey:@"switchValue"] boolValue];
[view addSubview:switchView];
return view;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 50;
}
- (void)switchChanged:(UISwitch *)sender {
NSMutableDictionary *dict = [self.theData objectAtIndex:sender.tag - 101];
[dict setValue:[NSNumber numberWithBool:sender.isOn] forKey:@"switchValue"];
[self.tableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
BOOL switchValue = [[self.theData[section] valueForKey:@"switchValue"] boolValue];
if (switchValue) {
return [[self.theData[section] valueForKey:@"rowData"] count];
}else{
return 0;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
cell.textLabel.text = [[self.theData[indexPath.section]valueForKey:@"rowData"]objectAtIndex:indexPath.row] ;
return cell;
}
我的kSwitchTagRange被#定义为101。这段代码可以折叠开关关闭的任何部分的行(实际上去掉所有行)
从这里的帖子中可以看出,viewForHeaderInSection返回的UIView已被释放,必须重新创建(以及它的所有子视图,包括我的UISwitch),而不是重新使用。我相信苹果认为你的节头比你的单元格要少得多,因此没有提供一个可重用的机制来检索节头。@rdelmar提出的数据绑定方法似乎对这种情况有意义。