tableview 中的 UIDatePicker 有时无法更改
UIDatePicker in tableview can't be changed sometimes
有时我在使用 UIDatePicker 时遇到问题。我构建了一个带有 UITableView 的屏幕,我可以在其中设置一周中每一天的开始时间和结束时间。
但是,现在我有一种奇怪的行为,即选择器有时不允许更改。它呈灰色但未禁用。当我转动选择器时,它会移动,但当我放手时,它会自动 returns 恢复到之前的值。
该行为是可重现的。我改变了一天并关闭了选择器。改天并关闭选择器。然后我向下滚动一点,tableview 轻微地抽动。如果我现在打开最后更改的选择器,我就会出现上述行为。我注意到 iOS 9 到 11 和不同设备上的行为。
为了更好地理解,我创建了一个 screenshot。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"timeProfilSettingsCell";
TimeProfilSettingsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDate *dateValidFrom = nil;
NSDate *dateValidUntil = nil;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"HH:mm"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
if (cell == nil)
{
[tableView registerNib:[UINib nibWithNibName:@"TimeProfilSettingsCell" bundle:nil] forCellReuseIdentifier:CellIdentifier];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
}
TimeInterval *timeInterval = [nma_currentTimeInterval objectAtIndex:indexPath.row];
if (timeInterval.ni_validFrom == TIMEPROFIL_VALUE_ALWAYS_VALID_FROM && timeInterval.ni_validUntil == TIMEPROFIL_VALUE_ALWAYS_VALID_UNTIL && timeInterval.ni_timeIntervalWeekdayActive == 1)
{
[cell.checkBoxImageView setImage:[UIImage imageNamed:@"IconHakenBlau"]];
}
else if (timeInterval.ni_timeIntervalWeekdayActive == 1)
{
[cell.checkBoxImageView setImage:[UIImage imageNamed:@"Clock_blue"]];
}
else
{
[cell.checkBoxImageView setImage:[UIImage imageNamed:@"IconOvalBlau"]];
}
cell.separatorView.backgroundColor = [UIColor colorWithRed:227.0/255.0 green:227.0/255.0 blue:227.0/255.0 alpha:1.0];
cell.weekDayLabel.text = [self getWeekDayName:indexPath.row];
[cell.checkBoxButton addTarget:self action:@selector(checkBoxButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.checkBoxButton setTag:indexPath.row];
cell.validityLabel.textColor = [UIColor colorWithRed:123.0/255.0 green:164.0/255.0 blue:219.0/255.0 alpha:1.0];
[cell.validityButton addTarget:self action:@selector(validityButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.validityButton setTag:indexPath.row];
// Handling so that the picker is closed when it is clicked elsewhere
UITapGestureRecognizer *tapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissDatePicker:)];
tapGestureRecognize.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapGestureRecognize];
BOOL b_open = NO;
if (b_pickerVisible && ni_touchedRow == indexPath.row)
{
b_open = YES;
cell.b_validityPickerVisible = YES;
[cell.validityStartPicker setHidden:NO];
[cell.validityStartPicker setEnabled:YES];
[cell.validityEndPicker setHidden:NO];
[cell.validityEndPicker setEnabled:YES];
cell.validityFromLabel.hidden = NO;
[cell.separatorView setFrame:CGRectMake(cell.separatorView.frame.origin.x, 304, cell.separatorView.frame.size.width, cell.separatorView.frame.size.height)];
[cell.validityStartPicker setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
[cell.validityEndPicker setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
[cell.validityStartPicker addTarget:self action:@selector(updateValidityStartPicker:) forControlEvents:UIControlEventValueChanged];
[cell.validityEndPicker addTarget:self action:@selector(updateValidityEndPicker:) forControlEvents:UIControlEventValueChanged];
if (b_pickerJustOpened)
{
b_pickerJustOpened = NO;
if (tableView.contentOffset.y > 0)
{
tableView.contentOffset = CGPointMake(0, tableView.contentOffset.y + 102);
}
}
if (b_pickerValueChanged)
{
// Picker-value not changed
}
else if (timeInterval.ni_validFrom == TIMEPROFIL_VALUE_INVALID && timeInterval.ni_validUntil == TIMEPROFIL_VALUE_INVALID)
{
// Default value, if the entry was previously "not"
[cell.validityStartPicker setDate:[NSDate dateWithTimeIntervalSince1970:0x20 /* 8:00 */ * 900 /* 15 Minuten x 60 Sekunden */] animated:NO];
[cell.validityEndPicker setDate:[NSDate dateWithTimeIntervalSince1970:0x40 /* 16:00 */ * 900 /* 15 Minuten x 60 Sekunden */] animated:NO];
b_pickerValueChanged = YES;
[cell.validityLabel setTextColor:[UIColor redColor]];
}
else
{
[cell.validityStartPicker setDate:[NSDate dateWithTimeIntervalSince1970:timeInterval.ni_validFrom * 900 /* 15 Minuten x 60 Sekunden */] animated:NO];
[cell.validityEndPicker setDate:[NSDate dateWithTimeIntervalSince1970:(timeInterval.ni_validUntil + 1 /* +1 aufrunden auf die volle viertel Stunde*/) * 900 /* 15 Minuten x 60 Sekunden */] animated:NO];
}
}
else
{
cell.b_validityPickerVisible = NO;
cell.validityStartPicker.hidden = YES;
cell.validityEndPicker.hidden = YES;
cell.validityFromLabel.hidden = YES;
[cell.validityStartPicker setEnabled:YES];
[cell.validityEndPicker setEnabled:YES];
[cell.separatorView setFrame:CGRectMake(cell.separatorView.frame.origin.x, 88, cell.separatorView.frame.size.width, cell.separatorView.frame.size.height)];
}
if (b_pickerValueChanged && ni_touchedRow == indexPath.row)
{
if ([[dateFormatter stringFromDate:[cell.validityEndPicker date]] isEqualToString:@"00:00"])
{
cell.validityLabel.text = [NSString stringWithFormat:@"%@ - 23:59:59 %@ >", [dateFormatter stringFromDate:[cell.validityStartPicker date]], NSLocalizedString(@"oClock", nil)];
}
else
{
cell.validityLabel.text = [NSString stringWithFormat:@"%@ - %@ %@ >", [dateFormatter stringFromDate:[cell.validityStartPicker date]], [dateFormatter stringFromDate:[cell.validityEndPicker date]], NSLocalizedString(@"oClock", nil)];
}
[cell.validityLabel setTextColor:[UIColor redColor]];
}
else if ((timeInterval.ni_validFrom == TIMEPROFIL_VALUE_ALWAYS_VALID_FROM && timeInterval.ni_validUntil == TIMEPROFIL_VALUE_ALWAYS_VALID_UNTIL && timeInterval.ni_timeIntervalWeekdayActive == 1) || (ni_flagTimeIntervalActive == 0 && timeInterval.ni_timeIntervalWeekdayActive == 1))
{
cell.validityLabel.text = NSLocalizedString(@"Always", nil);
}
else if (timeInterval.ni_validFrom == TIMEPROFIL_VALUE_INVALID || timeInterval.ni_validUntil == TIMEPROFIL_VALUE_INVALID)
{
cell.validityLabel.text = NSLocalizedString(@"Not", nil);
}
else
{
timeInterval.ni_timeIntervalWeekdayActive = 1;
dateValidFrom = [NSDate dateWithTimeIntervalSince1970:timeInterval.ni_validFrom * 900 /* 15 Minuten x 60 Sekunden */];
dateValidUntil = [NSDate dateWithTimeIntervalSince1970:(timeInterval.ni_validUntil + 1 /* +1 aufrunden auf die volle viertel Stunde*/) * 900 /* 15 Minuten x 60 Sekunden */];
if (timeInterval.ni_validUntil == TIMEPROFIL_VALUE_ALWAYS_VALID_UNTIL)
{
cell.validityLabel.text = [NSString stringWithFormat:@"%@ - 23:59:59 %@", [dateFormatter stringFromDate:dateValidFrom], NSLocalizedString(@"oClock", nil)];
}
else
{
cell.validityLabel.text = [NSString stringWithFormat:@"%@ - %@ %@", [dateFormatter stringFromDate:dateValidFrom], [dateFormatter stringFromDate:dateValidUntil], NSLocalizedString(@"oClock", nil)];
}
}
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
我已将部分代码提取到一个项目中,并使其可用于 download。
我希望有人有想法。
感谢您的帮助
终于找到了解决问题的方法。在代码中设置语言环境后,选择器没有阻塞。
这是我在代码中 setTimeZone:
之后添加的代码。
[cell.validityStartPicker setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[NSLocale currentLocale] localeIdentifier]]];
[cell.validityEndPicker setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[NSLocale currentLocale] localeIdentifier]]];
有时我在使用 UIDatePicker 时遇到问题。我构建了一个带有 UITableView 的屏幕,我可以在其中设置一周中每一天的开始时间和结束时间。
但是,现在我有一种奇怪的行为,即选择器有时不允许更改。它呈灰色但未禁用。当我转动选择器时,它会移动,但当我放手时,它会自动 returns 恢复到之前的值。
该行为是可重现的。我改变了一天并关闭了选择器。改天并关闭选择器。然后我向下滚动一点,tableview 轻微地抽动。如果我现在打开最后更改的选择器,我就会出现上述行为。我注意到 iOS 9 到 11 和不同设备上的行为。
为了更好地理解,我创建了一个 screenshot。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"timeProfilSettingsCell";
TimeProfilSettingsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDate *dateValidFrom = nil;
NSDate *dateValidUntil = nil;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"HH:mm"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
if (cell == nil)
{
[tableView registerNib:[UINib nibWithNibName:@"TimeProfilSettingsCell" bundle:nil] forCellReuseIdentifier:CellIdentifier];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
}
TimeInterval *timeInterval = [nma_currentTimeInterval objectAtIndex:indexPath.row];
if (timeInterval.ni_validFrom == TIMEPROFIL_VALUE_ALWAYS_VALID_FROM && timeInterval.ni_validUntil == TIMEPROFIL_VALUE_ALWAYS_VALID_UNTIL && timeInterval.ni_timeIntervalWeekdayActive == 1)
{
[cell.checkBoxImageView setImage:[UIImage imageNamed:@"IconHakenBlau"]];
}
else if (timeInterval.ni_timeIntervalWeekdayActive == 1)
{
[cell.checkBoxImageView setImage:[UIImage imageNamed:@"Clock_blue"]];
}
else
{
[cell.checkBoxImageView setImage:[UIImage imageNamed:@"IconOvalBlau"]];
}
cell.separatorView.backgroundColor = [UIColor colorWithRed:227.0/255.0 green:227.0/255.0 blue:227.0/255.0 alpha:1.0];
cell.weekDayLabel.text = [self getWeekDayName:indexPath.row];
[cell.checkBoxButton addTarget:self action:@selector(checkBoxButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.checkBoxButton setTag:indexPath.row];
cell.validityLabel.textColor = [UIColor colorWithRed:123.0/255.0 green:164.0/255.0 blue:219.0/255.0 alpha:1.0];
[cell.validityButton addTarget:self action:@selector(validityButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.validityButton setTag:indexPath.row];
// Handling so that the picker is closed when it is clicked elsewhere
UITapGestureRecognizer *tapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissDatePicker:)];
tapGestureRecognize.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapGestureRecognize];
BOOL b_open = NO;
if (b_pickerVisible && ni_touchedRow == indexPath.row)
{
b_open = YES;
cell.b_validityPickerVisible = YES;
[cell.validityStartPicker setHidden:NO];
[cell.validityStartPicker setEnabled:YES];
[cell.validityEndPicker setHidden:NO];
[cell.validityEndPicker setEnabled:YES];
cell.validityFromLabel.hidden = NO;
[cell.separatorView setFrame:CGRectMake(cell.separatorView.frame.origin.x, 304, cell.separatorView.frame.size.width, cell.separatorView.frame.size.height)];
[cell.validityStartPicker setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
[cell.validityEndPicker setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
[cell.validityStartPicker addTarget:self action:@selector(updateValidityStartPicker:) forControlEvents:UIControlEventValueChanged];
[cell.validityEndPicker addTarget:self action:@selector(updateValidityEndPicker:) forControlEvents:UIControlEventValueChanged];
if (b_pickerJustOpened)
{
b_pickerJustOpened = NO;
if (tableView.contentOffset.y > 0)
{
tableView.contentOffset = CGPointMake(0, tableView.contentOffset.y + 102);
}
}
if (b_pickerValueChanged)
{
// Picker-value not changed
}
else if (timeInterval.ni_validFrom == TIMEPROFIL_VALUE_INVALID && timeInterval.ni_validUntil == TIMEPROFIL_VALUE_INVALID)
{
// Default value, if the entry was previously "not"
[cell.validityStartPicker setDate:[NSDate dateWithTimeIntervalSince1970:0x20 /* 8:00 */ * 900 /* 15 Minuten x 60 Sekunden */] animated:NO];
[cell.validityEndPicker setDate:[NSDate dateWithTimeIntervalSince1970:0x40 /* 16:00 */ * 900 /* 15 Minuten x 60 Sekunden */] animated:NO];
b_pickerValueChanged = YES;
[cell.validityLabel setTextColor:[UIColor redColor]];
}
else
{
[cell.validityStartPicker setDate:[NSDate dateWithTimeIntervalSince1970:timeInterval.ni_validFrom * 900 /* 15 Minuten x 60 Sekunden */] animated:NO];
[cell.validityEndPicker setDate:[NSDate dateWithTimeIntervalSince1970:(timeInterval.ni_validUntil + 1 /* +1 aufrunden auf die volle viertel Stunde*/) * 900 /* 15 Minuten x 60 Sekunden */] animated:NO];
}
}
else
{
cell.b_validityPickerVisible = NO;
cell.validityStartPicker.hidden = YES;
cell.validityEndPicker.hidden = YES;
cell.validityFromLabel.hidden = YES;
[cell.validityStartPicker setEnabled:YES];
[cell.validityEndPicker setEnabled:YES];
[cell.separatorView setFrame:CGRectMake(cell.separatorView.frame.origin.x, 88, cell.separatorView.frame.size.width, cell.separatorView.frame.size.height)];
}
if (b_pickerValueChanged && ni_touchedRow == indexPath.row)
{
if ([[dateFormatter stringFromDate:[cell.validityEndPicker date]] isEqualToString:@"00:00"])
{
cell.validityLabel.text = [NSString stringWithFormat:@"%@ - 23:59:59 %@ >", [dateFormatter stringFromDate:[cell.validityStartPicker date]], NSLocalizedString(@"oClock", nil)];
}
else
{
cell.validityLabel.text = [NSString stringWithFormat:@"%@ - %@ %@ >", [dateFormatter stringFromDate:[cell.validityStartPicker date]], [dateFormatter stringFromDate:[cell.validityEndPicker date]], NSLocalizedString(@"oClock", nil)];
}
[cell.validityLabel setTextColor:[UIColor redColor]];
}
else if ((timeInterval.ni_validFrom == TIMEPROFIL_VALUE_ALWAYS_VALID_FROM && timeInterval.ni_validUntil == TIMEPROFIL_VALUE_ALWAYS_VALID_UNTIL && timeInterval.ni_timeIntervalWeekdayActive == 1) || (ni_flagTimeIntervalActive == 0 && timeInterval.ni_timeIntervalWeekdayActive == 1))
{
cell.validityLabel.text = NSLocalizedString(@"Always", nil);
}
else if (timeInterval.ni_validFrom == TIMEPROFIL_VALUE_INVALID || timeInterval.ni_validUntil == TIMEPROFIL_VALUE_INVALID)
{
cell.validityLabel.text = NSLocalizedString(@"Not", nil);
}
else
{
timeInterval.ni_timeIntervalWeekdayActive = 1;
dateValidFrom = [NSDate dateWithTimeIntervalSince1970:timeInterval.ni_validFrom * 900 /* 15 Minuten x 60 Sekunden */];
dateValidUntil = [NSDate dateWithTimeIntervalSince1970:(timeInterval.ni_validUntil + 1 /* +1 aufrunden auf die volle viertel Stunde*/) * 900 /* 15 Minuten x 60 Sekunden */];
if (timeInterval.ni_validUntil == TIMEPROFIL_VALUE_ALWAYS_VALID_UNTIL)
{
cell.validityLabel.text = [NSString stringWithFormat:@"%@ - 23:59:59 %@", [dateFormatter stringFromDate:dateValidFrom], NSLocalizedString(@"oClock", nil)];
}
else
{
cell.validityLabel.text = [NSString stringWithFormat:@"%@ - %@ %@", [dateFormatter stringFromDate:dateValidFrom], [dateFormatter stringFromDate:dateValidUntil], NSLocalizedString(@"oClock", nil)];
}
}
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
我已将部分代码提取到一个项目中,并使其可用于 download。
我希望有人有想法。
感谢您的帮助
终于找到了解决问题的方法。在代码中设置语言环境后,选择器没有阻塞。
这是我在代码中 setTimeZone:
之后添加的代码。
[cell.validityStartPicker setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[NSLocale currentLocale] localeIdentifier]]];
[cell.validityEndPicker setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[NSLocale currentLocale] localeIdentifier]]];