我正在尝试找出向UITableView标头添加和管理UISwitch的最佳方法,到目前为止,我已经阅读了几个关于如何在表格中最好地使用UISwitch的链接:here,{ {3}}和here。这些链接演示了在单元格中使用UISwitch,而我在自定义UIView中使用它们作为标题。也就是说,我更愿意使用标签来管理这些对象,但我无法弄清楚为什么viewWithTag方法无效。
附注:我能够在运行时将UISwitches放入NSMutableArray并以这种方式管理它们,但我宁愿不那么冗长,管理数组上的边界违规/索引或检查nil列表等等...我还不清楚如何使用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并确定它处于开/关状态,然后如果OFF则返回0表示该行中的行数,如果为ON则返回其他一些数字:
- (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始终是零。
我有一些猜测,但不能确定为什么会发生这种情况。
有谁能告诉我为什么上面的viewWithTag方法会返回nil?我倾向于猜测#1但是没有找到任何文档告诉我UIView随时被解除分配。这些单元格被重用了,但是节标题呢?
最后,我已阅读here,虽然有关标记使用的建议有意义但似乎完全不喜欢标记方法。为什么不使用标签,如果你没有发现使用它们是凌乱的,他们被智能地使用?为什么标签功能可用?
真的,我只是想知道为什么viewWithTag方法在我的情况下返回nil。
干杯!
答案 0 :(得分:1)
我不确定为什么你的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 #defined为101.此代码用于在交换机关闭的任何部分中折叠行(实际上除去所有行)。
答案 1 :(得分:0)
从帖子here看来,viewForHeaderInSection返回的UIView已被释放,必须重新创建(以及所有子视图,包括我的UISwitch),而不是重新使用。我相信Apple假设您的节标题比单元格少得多,因此没有提供用于检索节标题的可重用性机制。 @rdelmar提出的数据绑定方法似乎对这种情况有意义。