私は(ほとんどのアプリと同様に)自動回転をサポートするiPhoneアプリを書いています。電話を回転させると、そのビューが適切に回転およびサイズ変更されます。
しかし、カスタムビューをnavigationItem.titleView
(ナビゲーションバーのタイトル領域)に割り当てているので、電話が回転したときにそのビューのサイズを正しく変更できません。
「autoresizingMask
をUIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
に設定するだけです」とあなたが考えていることは知っていますが、それほど単純ではありません。もちろん、ビューのautoresizingMask
を設定しないと、ビューのサイズは変更されません。サイズを変更したい。
問題は、I doautoresizingMask
を設定すると、そのビューが表示されている限り、正しくサイズ変更されることです。しかし、このシナリオではtitleView
のサイズが台無しになります。
[self.navigationController pushViewController:someOtherViewController animated:YES]
を呼び出すテーブルの行またはボタンをクリックします。これを自分で再現したい場合は、次の手順に従ってください(これは少し作業です)。
このコードをトップレベルのビューコントローラーと詳細ビューコントローラーの両方に含めます。
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
このコードは、トップレベルのViewControllerにのみ含めてください。
- (void)viewDidLoad {
[super viewDidLoad];
// Create "Back" button
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Master"
style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];
// Create title view
UILabel* titleView = [[[UILabel alloc] initWithFrame:CGRectMake(0,0,500,38)] autorelease];
titleView.textAlignment = UITextAlignmentCenter;
titleView.text = @"Watch this title view";
// If I leave the following line turned on, then resizing of the title view
// messes up if I:
//
// 1. Start at the master view (which uses this title view) in portrait
// 2. Navigate to the detail view
// 3. Rotate the phone to landscape
// 4. Navigate back to the master view
// 5. Rotate the phone back to portrait
//
// On the other hand, if I remove the following line, then I get a different
// problem: The title view doesn't resize as I want it to when I:
//
// 1. Start at the master view (which uses this title view) in portrait
// 2. Rotate the phone to landscape
titleView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.navigationItem.titleView = titleView;
}
最後に、私の再現手順に従います。
だから...私は何か間違ったことをしていますか? titleViewのサイズを常に正しく変更する方法はありますか?
(私自身の質問に答える)
TitleViewのマージン(ナビゲーションバーの端からの距離)を手動で追跡することでこれを機能させました-ビューが消えたときに保存し、ビューが再び表示されたときに復元します。
アイデアは、titleViewを以前の正確なサイズに復元しないということです。むしろ、以前と同じmarginsになるように復元しています。そうすれば、電話が回転した場合、titleViewは新しい適切なサイズになります。
これが私のコードです:
私のビューコントローラーの.hファイル:
@interface MyViewController ...
{
CGRect titleSuperviewBounds;
UIEdgeInsets titleViewMargins;
}
私のビューコントローラーの.mファイル:
/**
* Helper function: Given a parent view's bounds and a child view's frame,
* calculate the margins of the child view.
*/
- (UIEdgeInsets) calcMarginsFromParentBounds:(CGRect)parentBounds
childFrame:(CGRect)childFrame {
UIEdgeInsets margins;
margins.left = childFrame.Origin.x;
margins.top = childFrame.Origin.y;
margins.right = parentBounds.size.width -
(childFrame.Origin.x + childFrame.size.width);
margins.bottom = parentBounds.size.height -
(childFrame.Origin.y + childFrame.size.height);
return margins;
}
- (void)viewDidUnload {
[super viewDidUnload];
titleSuperviewBounds = CGRectZero;
titleViewMargins = UIEdgeInsetsZero;
}
- (void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// Keep track of bounds information, so that if the user changes the
// phone's orientation while we are in a different view, then when we
// return to this view, we can fix the titleView's size.
titleSuperviewBounds = self.navigationItem.titleView.superview.bounds;
CGRect titleViewFrame = self.navigationItem.titleView.frame;
titleViewMargins = [self calcMarginsFromParentBounds:titleSuperviewBounds
childFrame:titleViewFrame];
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Check for the case where the user went into a different view, then
// changed the phone's orientation, then returned to this view. In that
// case, our titleView probably has the wrong size, and we need to fix it.
if (titleSuperviewBounds.size.width > 0) {
CGRect newSuperviewBounds =
self.navigationItem.titleView.superview.bounds;
if (newSuperviewBounds.size.width > 0 &&
!CGRectEqualToRect(titleSuperviewBounds, newSuperviewBounds))
{
CGRect newFrame = UIEdgeInsetsInsetRect(newSuperviewBounds,
titleViewMargins);
newFrame.size.height =
self.navigationItem.titleView.frame.size.height;
newFrame.Origin.y = floor((newSuperviewBounds.size.height -
self.navigationItem.titleView.frame.size.height) / 2);
self.navigationItem.titleView.frame = newFrame;
}
}
}
また、contentMode
のUIImageView
を設定して、titleView
が横向きまたは縦向きモードで正しく表示されるようにする必要があります。
imgView.contentMode=UIViewContentModeScaleAspectFit;
シーケンス全体:(自己はUIViewController
インスタンスです)
UIImageView* imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"myCustomTitle.png"]];
imgView.autoresizingMask=UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
imgView.contentMode=UIViewContentModeScaleAspectFit;
self.navigationItem.titleView = imgView;
[imgView release];
私は似たようなものを持っていました-しかしそれはルートビューコントローラーに戻っていました(ポップしていました)。最終的に、私はポップのために以下を使用しました:
[[self navigationController] setNavigationBarHidden:YES animated:NO];
[[self navigationController] popViewControllerAnimated:YES];
[[self navigationController] setNavigationBarHidden:NO animated:NO];
そしてそれはうまくいった。もっと良い方法があったかもしれませんが、私がこの問題にすでに費やしたすべての時間の後、これは私にとって十分でした。
この同じ問題に対処するために、customViewの初期フレームを追跡し、UIButtonサブクラスの-setLandscapeメソッドでそれと初期フレームのスケーリングされたCGRectを切り替えました。 UIButtonサブクラスをnavigationItem.titleViewおよびnavigationItem.rightBarButtonItemとして使用しました。
UIButtonサブクラス内-
- (void)setLandscape:(BOOL)value
{
isLandscape = value;
CGFloat navbarPortraitHeight = 44;
CGFloat navbarLandscapeHeight = 32;
CGRect initialFrame = // your initial frame
CGFloat scaleFactor = floorf((navbarLandscapeHeight/navbarPortraitHeight) * 100) / 100;
if (isLandscape) {
self.frame = CGRectApplyAffineTransform(initialFrame, CGAffineTransformMakeScale(scaleFactor, scaleFactor));
} else {
self.frame = initialFrame;
}
}
次に、InterfaceOrientationデリゲートで、customViewsの-setLandscapeメソッドを呼び出してサイズを変更しました。
UIViewControllerの場合-
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self updateNavbarButtonsToDeviceOrientation];;
}
- (void)updateNavbarButtonsToDeviceOrientation
{
ResizeButton *rightButton = (ResizeButton *)self.navigationItem.rightBarButtonItem.customView;
ResizeButton *titleView = (ResizeButton *)self.navigationItem.titleView;
if (self.interfaceOrientation == UIDeviceOrientationPortrait || self.interfaceOrientation == UIDeviceOrientationPortraitUpsideDown) {
[rightButton setLandscape:NO];
[titleView setLandscape:NO];
} else {
[rightButton setLandscape:YES];
[titleView setLandscape:YES];
}
}
IOS5以降の場合、これは古い質問であるため...これは、タイトルテキストが正しく配置されないという同じ問題をどのように達成したかです。
[[UINavigationBar appearance] setTitleVerticalPositionAdjustment:2 forBarMetrics:UIBarMetricsLandscapePhone];
Ios5/6シムでテスト済みは正常に動作します。
これは私がしたことです:
self.viewTitle.frame = self.navigationController.navigationBar.frame;
self.navigationItem.titleView = self.viewTitle;
ViewTitleは、xibで作成されたビューであり、navigationBarのサイズを取り、titleViewが追加された後、サイズを調整して、戻るボタンに余裕を持たせます。回転はうまく機能しているようです。
同じ問題が発生しましたが、次のコードで回避策が得られるようです。
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
UIView *urlField = self.navigationItem.leftBarButtonItem.customView;
CGRect frame = urlField.frame;
frame.size.width = 1000;
urlField.frame = frame;
}
私の場合、カスタムビューはUITextFieldですが、これがお役に立てば幸いです。