В моем UITableView
есть набор пользовательских ячеек, которые содержат UITextField
.Я обнаружил (трудный путь), что, по-видимому, выход из текущего представления (либо путем нажатия на новый контроллер представления, либо отклонение активного представления («назад»)) приведет к сбою моего приложения, когда клавиатура все еще видна.
Чтобы скрыть клавиатуру, когда пользователь все еще редактирует UITextField
, но вид изменился, я добавил [self.view endEditing:YES];
непосредственно перед тем, как нажать новый контроллер вида, а также в методе viewWillDisappear
.
Теперь мое приложение дает сбой только 1 из 5 попыток скрыть клавиатуру. Здесь Я, вероятно, узнал причину этого: когда ячейка перемещается за пределы экрана, она уничтожается / перерабатывается, поэтому при необходимости ее можно удалить из очереди.Это означает, что, как только моя ячейка и содержащиеся в ней текстовые поля переместятся за пределы экрана, отправив ей сообщение resignFirstResponder
(либо вручную, либо [self.view endEditing:YES];
, приложение выйдет из строя. Это обратная трассировка:
#0 0x012e309b in objc_msgSend ()
#1 0x05956888 in dyld_stub_usleep ()
#2 0x003ff056 in -[UIResponder resignFirstResponder] ()
#3 0x003c697f in -[UITextField resignFirstResponder] ()
#4 0x003c6ab1 in -[UIView(UITextField) endEditing:] ()
#5 0x00012c0a in -[MyController viewWillDisappear:] (self=0x7419e90, _cmd=0x52aa27e, animated=1 '\001') at MyController:121
#6 0x003ee9a2 in -[UINavigationController _startTransition:fromViewController:toViewController:] ()
#7 0x003e932a in -[UINavigationController _startDeferredTransitionIfNeeded] ()
#8 0x003e8fb6 in -[UINavigationController _popViewControllerWithTransition:allowPoppingLast:] ()
#9 0x003e9142 in -[UINavigationController popViewControllerAnimated:] ()
#10 0x003e857a in -[UINavigationController navigationBar:shouldPopItem:] ()
#11 0x00389260 in -[UINavigationBar _popNavigationItemWithTransition:] ()
#12 0x0039261b in -[UINavigationBar _handleMouseUpAtPoint:] ()
#13 0x00354ded in -[UIWindow _sendTouchesForEvent:] ()
#14 0x00335c37 in -[UIApplication sendEvent:] ()
#15 0x0033af2e in _UIApplicationHandleEvent ()
#16 0x01ad5992 in PurpleEventCallback ()
#17 0x0115e944 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
#18 0x010becf7 in __CFRunLoopDoSource1 ()
#19 0x010bbf83 in __CFRunLoopRun ()
#20 0x010bb840 in CFRunLoopRunSpecific ()
#21 0x010bb761 in CFRunLoopRunInMode ()
#22 0x01ad41c4 in GSEventRunModal ()
#23 0x01ad4289 in GSEventRun ()
#24 0x0033ec93 in UIApplicationMain ()
#25 0x00001e18 in main (argc=1, argv=0xbffff0a0) at main.m:24
Теперь у меня вопрос, как мне правильно скрыть клавиатуру UITextField
внутри моего UITableViewCell
во всех ситуациях? (Табличное представление исчезает, новый контроллер представления перемещается, ячейка / текстовое поле перемещается за пределы экранаи т. д.)
Любая помощь очень важна, я просто не могу избавиться от сбоев!
Я включу еще немного кода:
1) Пользовательский класс ячейки:
#import <UIKit/UIKit.h>
enum Type
{
tpText = 0,
tpInteger,
tpDecimal,
tpNumber
};
@protocol TextInputCellDelegate <NSObject>
@required
- (void)setNewText:(NSString*)newText forIndex:(NSIndexPath*)index;
@end
@interface TextInputCell : UITableViewCell <UITextFieldDelegate> {
IBOutlet UILabel* mainText;
IBOutlet UITextField* textField;
NSNumberFormatter* numberFormatter;
int type;
id <TextInputCellDelegate> delegate;
}
- (void) initDelegateWithType:(int)aType;
- (void) save:(NSString*)text;
- (void) startEditing;
@property (nonatomic, retain) UILabel* mainText;
@property (nonatomic, retain) UITextField* textField;
@property (nonatomic, retain) NSNumberFormatter* numberFormatter;
@property (nonatomic, assign) int type;
@property (nonatomic, assign) id <TextInputCellDelegate> delegate;
@end
Реализация пользовательской ячейки:
#import "TextInputCell.h"
@implementation TextInputCell
@synthesize mainText;
@synthesize textField;
@synthesize numberFormatter;
@synthesize type;
@synthesize delegate;
- (void) initDelegateWithType:(int)aType {
self.type = aType;
textField.delegate = self;
}
- (BOOL)textField:(UITextField *)aTextField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; {
if (![string length] || type == tpText || (isnumber([string characterAtIndex:0]) && type == tpNumber))
{
[self save:[textField.text stringByReplacingCharactersInRange:range withString:string]];
return YES;
}
char c = [string characterAtIndex:0];
BOOL isSep = [string isEqualToString:[numberFormatter decimalSeparator]];
BOOL isMinus = [string isEqualToString:@"-"];
NSRange sep;
sep.location = NSNotFound;
sep.length = 0;
if ([aTextField.text length])
sep = [aTextField.text rangeOfString:[numberFormatter decimalSeparator]];
if (isMinus)
{
// allow '-' only if type is tpNumber and field is empty
if (type != tpNumber)
return NO;
if ([aTextField.text length])
return NO;
[self save:[textField.text stringByReplacingCharactersInRange:range withString:string]];
return YES;
}
if (isnumber(c) || ((type == tpDecimal || type == tpNumber) && isSep && sep.location == NSNotFound))
{
// allow separator for decimal and number, but only if not in text already
if (!isSep && sep.location != NSNotFound && type == tpDecimal)
{
// round after , (only for decimal type)
NSString* text = [NSString stringWithFormat:@"%@%@", aTextField.text, string];
double num = [[numberFormatter numberFromString:text] doubleValue];
double res = ((int)(num / 0.5)) * 0.5;
aTextField.text = [numberFormatter stringFromNumber:[NSNumber numberWithDouble:res]];
[self save:aTextField.text];
return NO;
}
[self save:[NSString stringWithFormat:@"%@%@", aTextField.text, string]];
return YES;
}
[self save:[NSString stringWithFormat:@"%@%@", aTextField.text, string]];
return NO;
}
- (void) save:(NSString*)text {
UITableView* view = (UITableView*)[self superview];
NSIndexPath* index = [view indexPathForCell:self];
if (delegate)
[delegate setNewText:text forIndex:index];
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)field
{
NSLog(@"should end");
// if ([field becomeFirstResponder])
// [field resignFirstResponder];
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)field {
if (type != tpText && [field.text length] == 0)
field.text = @"0";
NSLog(@"should return");
// if ([field becomeFirstResponder])
// [field resignFirstResponder];
return YES;
}
- (void) startEditing {
NSLog(@"should return");
[self.textField becomeFirstResponder];
}
@end
Просмотр контроллера, который содержит 4 из этих ячеек:
@implementation MailPrefController
@synthesize menuItems;
@synthesize mailTo;
@synthesize mailCc;
@synthesize mailBcc;
@synthesize mailSubject;
@synthesize mailBody;
#pragma mark -
#pragma mark Initialization
- (id)initWithStyle:(UITableViewStyle)style {
// Override initWithStyle: if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
if ((self = [super initWithStyle:UITableViewStyleGrouped])) {
}
return self;
}
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
// save button
UIBarButtonItem* saveButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(saveMailPrefs)];
self.navigationItem.rightBarButtonItem = saveButton;
[saveButton release];
self.navigationItem.title = NSLocalizedString(@"Mail template", nil);
// menu items
self.menuItems = [[NSArray alloc] initWithObjects:NSLocalizedString(@"To:", nil), NSLocalizedString(@"Cc:", nil), NSLocalizedString(@"Bcc:", nil), NSLocalizedString(@"Subject:", nil), NSLocalizedString(@"Body:", nil), nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [menuItems count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row < 4)
{
// title
TextInputCell* textCell = (TextInputCell*)[tableView dequeueReusableCellWithIdentifier:@"TextInputCell"];
if (textCell == nil)
{
NSArray* nibContents = [[NSBundle mainBundle] loadNibNamed:@"TextInputCell" owner:self options:nil];
textCell = [nibContents lastObject];
textCell.selectionStyle = UITableViewCellSelectionStyleNone;
textCell.textField.textColor = [Service uiColor];
textCell.delegate = self;
[textCell initDelegateWithType:tpText];
}
textCell.mainText.text = [menuItems objectAtIndex:indexPath.row];
switch (indexPath.row)
{
case 0: textCell.textField.text = self.mailTo; break;
case 1: textCell.textField.text = self.mailCc; break;
case 2: textCell.textField.text = self.mailBcc; break;
case 3: textCell.textField.text = self.mailSubject; break;
default: break;
}
return textCell;
}
// body text multiline
TextInputMultilineCell* textMultilineCell = (TextInputMultilineCell*)[tableView dequeueReusableCellWithIdentifier:@"TextInputMultilineCell"];
if (textMultilineCell == nil)
{
NSArray* nibContents = [[NSBundle mainBundle] loadNibNamed:@"TextInputMultilineCell" owner:self options:nil];
textMultilineCell = [nibContents lastObject];
textMultilineCell.selectionStyle = UITableViewCellSelectionStyleNone;
textMultilineCell.textView.font = [UIFont systemFontOfSize:12];
textMultilineCell.textView.textColor = [Service uiColor];
textMultilineCell.delegate = self;
[textMultilineCell initDelegate];
CGRect rect = textMultilineCell.textView.frame;
rect.size.height *= 2;
textMultilineCell.textView.frame = rect;
}
textMultilineCell.mainText.text = [menuItems objectAtIndex:indexPath.row];
textMultilineCell.textView.text = self.mailBody;
return textMultilineCell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.section)
{
case 0:
{
// general section
if (indexPath.row < 4)
{
TextInputCell* cell = (TextInputCell*)[[self tableView] cellForRowAtIndexPath:indexPath];
[cell startEditing];
}
}
default: break;
}
}
Сбой можно воспроизвести, нажав однуиз ячеек с UITextField
сдвиньте экран выключения ячеек (не скрывая клавиатуру), а затем просто отклоните просмотр таблицы (например, вернитесь через навигационный контроллер).
Может ли это быть вызвано ручным открытием клавиатуры, когдаячейка нажата?(startEditing
метод) Я делаю это, чтобы пользователю не нужно было нажимать текстовое поле, но редактирование также начинается, когда он, например, касается текстовой метки ячеек.