私のiPadアプリでは、ネット上にあるイディオムを使用して、UIAlertView2つを追加するサブクラスとしてログインウィンドウを実装しています。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;
}
実用的なソリューションを提供してくれたBittuに感謝します。これが彼のアイデアの私の実装です。サブクラスの新しいメソッドにアラートを上に移動するコードを配置しました。
- (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];
}
重要なポイントは、そのコードをいつ呼び出すかです。2つのケースがあります。最も単純なケースは、ユーザーがデバイスを回転させる場合です。残念ながら、Alertクラスにはそのイベントが通知されず、クライアントUIViewControllerのみが通知されるため、呼び出す必要があります。これはカプセル化を破ることによって醜いですが、そうです:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if(loginWindow && UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
{
[loginWindow slideUp];
}
}
2番目のケースは、アラートを開いたときに方向がすでに水平になっている場合です。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それでも機能するようです。それが気になる場合は、正しいシグネチャを使用してbetweenメソッドを追加するだけです。
- (void)slideUpByTimer:(NSTimer*)theTimer
{
[self slideUp];
}