В моем приложении для iPad есть окно входа в систему как подкласс UIAlertView
, которое добавляет два UITextField
с использованием идиомы, найденной в сети.
Проблема в том, что в горизонтальной ориентации предупреждение частично скрыто клавиатурой. А именно кнопки скрыты. Конечно, можно скрыть клавиатуру, чтобы открыть кнопку, но это ужасно.
Способ, которым должна исправить идиома, это добавить преобразование перевода в представление:
CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, 100.0);
[self setTransform:translate];
Однако на самом деле это не работает:
- в исходной вертикальной ориентации, которая работает (но перестает работать после любого вращения устройства)
- в исходной горизонтальной ориентации можно увидеть, как оно работает, но предупреждение сразу же возвращается к центру экрана, где оно снова частично скрыто.
- в любой ориентации после вращения iPad он вообще не работает: ничего не происходит, как будто преобразования даже не было.
(кроме того, эта идея преобразования может перестать {работать | быть необходимой} для iOS 4.x. Но это другая проблема).
Любая идея приветствуется.
Для полноты, вот полный код:
- (id)initWithLogin:(NSString *)defaultLogin delegate:(id)delegate
{
if (self = [super initWithTitle:@"Username and password"
message:@"\n\n\n"
delegate:delegate
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Enter", nil])
{
UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(12.0, 45.0, 260.0, 25.0)];
[theTextField setBackgroundColor:[UIColor whiteColor]];
theTextField.text = defaultLogin;
theTextField.placeholder = @"username";
[self addSubview:theTextField];
self.loginField = theTextField;
[theTextField release];
theTextField = [[UITextField alloc] initWithFrame:CGRectMake(12.0, 80.0, 260.0, 25.0)];
[theTextField setBackgroundColor:[UIColor whiteColor]];
theTextField.placeholder = @"password";
theTextField.secureTextEntry = YES;
[self addSubview:theTextField];
self.passwordField = theTextField;
[theTextField release];
// the two next lines may not be useful for iOS > 4.0
CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, 100.0);
[self setTransform:translate];
}
return self;
}
Спасибо за Битту за рабочее решение. Вот моя реализация его идеи. Я поместил код для перемещения оповещения в новый метод моего подкласса:
- (void)slideUp
{
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.25f];
CGPoint center = self.center;
center.y -= 100;
self.center = center;
[UIView commitAnimations];
}
Ключевой момент - когда вызывать этот код. Есть два случая: самый простой случай, когда пользователь поворачивает устройство. К сожалению, класс Alert не проинформирован об этом событии, только клиентский UIViewController, поэтому нам нужно было его вызвать. Это уродливо, нарушая инкапсуляцию, но пусть будет так:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if(loginWindow && UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
{
[loginWindow slideUp];
}
}
Второй случай, когда при открытии оповещения ориентация уже горизонтальная. Делегат оповещения информируется об этом в своем методе делегата didPresentAlertView:
.
- (void)didPresentAlertView:(UIAlertView *)alertView
{
if ( UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ) {
[self slideUp];
}
}
К сожалению, эта реализация не работает, потому что вызов slideUp
в это время будет конфликтовать с системой, уже анимирующей предупреждение к центру экрана. Решение состоит в том, чтобы немного задержать вызов, например, используя NSTimer
:
- (void)didPresentAlertView:(UIAlertView *)alertView
{
if ( UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ) {
[NSTimer scheduledTimerWithTimeInterval:0.25f
target:self
selector:@selector(slideUp)
userInfo:nil
repeats:NO];
}
}
Кстати, slideUp
не имеет документированной подписи для селектора NSTimer
, но, похоже, все еще работает! Если это вас беспокоит, просто добавьте промежуточный метод с правильной подписью:
- (void)slideUpByTimer:(NSTimer*)theTimer
{
[self slideUp];
}