注意:这可能与Subview Doesnt AutoSize When Added to Root View Controller
重复我有一个iPad应用程序,可以在主窗口中的不同视图之间切换。视图切换代码如下所示:
- (void)switchToViewController:(UIViewController*)viewController {
if (currentViewController != viewController) {
[currentViewController.view removeFromSuperview];
currentViewController = viewController;
[window addSubview:viewController.view];
}
}
问题在于,当新视图(UISplitView)以横向方向显示时,其大小不足以填充整个窗口。右边有一个空的黑色大空间。看起来视图只有768像素宽,而不是景观窗口的1024像素宽度。
如果我将设备旋转为纵向然后再回到横向,则视图会自行调整大小。
如果设备处于纵向,一切正常。如果它是我展示的第一个视图,UISplitView也会正确调整大小。如果我在横向显示另一个视图后切换到它,则只会出现此问题。
那么,是否有某种方法可以强制iPhone OS在将视图添加到窗口后调整其大小?
我尝试过调用sizeToFit
和setNeedsLayout
。我也尝试将视图的bounds
设置为窗口bounds
,我尝试将frame
设置为与上一个视图的帧匹配。
答案 0 :(得分:9)
绝对有可能! : - )强>
你可以在这里查看我的回购: https://github.com/hfossli/AGWindowView
它将自动处理任何旋转和帧更改,因此您不必担心。
如果您想担心这一点,那么您可以剪切并粘贴最重要的部分
#1将视图添加到窗口
[[UIApplication sharedApplication] keyWindow] addSubview:aView];
#2添加监听器和更新视图
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameOrOrientationChanged:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameOrOrientationChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
请记住删除通知收听
[[NSNotificationCenter defaultCenter] removeObserver:self];
#3做数学
- (void)statusBarFrameOrOrientationChanged:(NSNotification *)notification
{
/*
This notification is most likely triggered inside an animation block,
therefore no animation is needed to perform this nice transition.
*/
[self rotateAccordingToStatusBarOrientationAndSupportedOrientations];
}
- (void)rotateAccordingToStatusBarOrientationAndSupportedOrientations
{
UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
CGFloat angle = UIInterfaceOrientationAngleOfOrientation(statusBarOrientation);
CGFloat statusBarHeight = [[self class] getStatusBarHeight];
CGAffineTransform transform = CGAffineTransformMakeRotation(angle);
CGRect frame = [[self class] rectInWindowBounds:self.window.bounds statusBarOrientation:statusBarOrientation statusBarHeight:statusBarHeight];
[self setIfNotEqualTransform:transform frame:frame];
}
- (void)setIfNotEqualTransform:(CGAffineTransform)transform frame:(CGRect)frame
{
if(!CGAffineTransformEqualToTransform(self.transform, transform))
{
self.transform = transform;
}
if(!CGRectEqualToRect(self.frame, frame))
{
self.frame = frame;
}
}
+ (CGFloat)getStatusBarHeight
{
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if(UIInterfaceOrientationIsLandscape(orientation))
{
return [UIApplication sharedApplication].statusBarFrame.size.width;
}
else
{
return [UIApplication sharedApplication].statusBarFrame.size.height;
}
}
+ (CGRect)rectInWindowBounds:(CGRect)windowBounds statusBarOrientation:(UIInterfaceOrientation)statusBarOrientation statusBarHeight:(CGFloat)statusBarHeight
{
CGRect frame = windowBounds;
frame.origin.x += statusBarOrientation == UIInterfaceOrientationLandscapeLeft ? statusBarHeight : 0;
frame.origin.y += statusBarOrientation == UIInterfaceOrientationPortrait ? statusBarHeight : 0;
frame.size.width -= UIInterfaceOrientationIsLandscape(statusBarOrientation) ? statusBarHeight : 0;
frame.size.height -= UIInterfaceOrientationIsPortrait(statusBarOrientation) ? statusBarHeight : 0;
return frame;
}
CGFloat UIInterfaceOrientationAngleOfOrientation(UIInterfaceOrientation orientation)
{
CGFloat angle;
switch (orientation)
{
case UIInterfaceOrientationPortraitUpsideDown:
angle = M_PI;
break;
case UIInterfaceOrientationLandscapeLeft:
angle = -M_PI_2;
break;
case UIInterfaceOrientationLandscapeRight:
angle = M_PI_2;
break;
default:
angle = 0.0;
break;
}
return angle;
}
UIInterfaceOrientationMask UIInterfaceOrientationMaskFromOrientation(UIInterfaceOrientation orientation)
{
return 1 << orientation;
}
祝你好运!
答案 1 :(得分:3)
这很有效,但看起来有点hacky:
- (void)switchToViewController:(UIViewController *)viewController {
if (viewController != currentViewController) {
UIInterfaceOrientation orientation = currentViewController.interfaceOrientation;
[currentViewController.view removeFromSuperview];
currentViewController = viewController;
UIView *view = viewController.view;
// Set appropriate view frame (it won't be autosized by addSubview:)
CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
if (UIInterfaceOrientationIsLandscape(orientation)) {
// Need to flip the X-Y coordinates for landscape
view.frame = CGRectMake(appFrame.origin.y, appFrame.origin.x, appFrame.size.height, appFrame.size.width);
}
else {
view.frame = appFrame;
}
[window addSubview:view];
}
}
答案 2 :(得分:1)
窗口可能包含视图之外的其他UI元素。示例中的20像素差异是状态栏的高度。
[[UIApplication sharedApplication] statusBarFrame].height;
窗口和屏幕都不会旋转。获取框架并将其用于旋转视图仅在切换高度和宽度时才有效。
如果您使用的是UIViewController,请尝试从此方法返回YES:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation; // Override to allow rotation. Default returns YES only for UIDeviceOrientationPortrait
答案 3 :(得分:1)
我遇到了同样的问题,但我用这行代码修复了它:
- (void)changeRow:(NSNotification *)notification {
[window addSubview:new.view];
[old.view removeFromSuperview];
[new.view removeFromSuperview];
[window addSubview:new.view];
}
您必须添加新视图,然后删除旧视图和新视图,然后添加新视图。我不知道为什么,但那确实有效。
答案 4 :(得分:1)
Fossli对iPad的回答是正确的。但是,我有一个我需要支持的通用应用程序。因此需要进行一些调整。
将以下内容添加到AppDelegate.h
@property (strong, nonatomic) UIImageView *imageView;
将以下内容添加到AppDelegate.m
@synthesize imageView;
- (void)orientationChanged:(NSNotification *)notification
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (! (UIInterfaceOrientationIsLandscape(deviceOrientation) ||
UIInterfaceOrientationIsPortrait(deviceOrientation)))
{
// May be "UIInterfaceOrientationUnknown" which does not appear to be a defined value anywhere.
return;
}
[imageView setImage:[UIImage imageNamed:[Utility getBackgroundImageNameWithOrientation:deviceOrientation]]];
/*
iOS Image Sizes
iPhone/iPod Portrait 320 x 480 (640 x 960 @2x)
iPad Portrait 768 x 1004 (1536 x 2008 @2x)
Landscape 1024 x 748 (2048 x 1496 @2x)
iPad window bounds in both orientations 768 x 1024 (needs manual swap in landscape)
iPhone window bounds in both orientations 320 x 480 (needs manual swap in landscape)
Note the size variations between the required default launch image sizes and
the size of the window bounds.
iPhone/iPod only requires rotations.
iPad needs origin or size adjustments depending on orientation.
*/
CGFloat angle = 0.0;
CGRect newFrame = [[self window] bounds];
// How to get size of status bar
// Size of status bar gets all wonky on rotations so just set it manually
// CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
CGSize statusBarSize = CGSizeMake(20.0, 20.0);
if (deviceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
angle = M_PI;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
{
newFrame.size.height -= statusBarSize.height;
}
}
else if (deviceOrientation == UIInterfaceOrientationLandscapeLeft)
{
angle = - M_PI / 2.0f;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
{
newFrame.origin.x += statusBarSize.height;
newFrame.size.width += statusBarSize.height;
}
}
else if (deviceOrientation == UIInterfaceOrientationLandscapeRight)
{
angle = M_PI / 2.0f;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
{
newFrame.size.width -= statusBarSize.height;
}
}
else
{
angle = 0.0;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
{
newFrame.origin.y += statusBarSize.height;
newFrame.size.height -= statusBarSize.height;
}
}
imageView.transform = CGAffineTransformMakeRotation(angle);
imageView.frame = newFrame;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Add background image to window with orientation changes so that it is visible in all views.
// A listener is added since subviews do not receive orientation changes.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object: nil];
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[Utility getBackgroundImageNameWithOrientation:deviceOrientation]]];
[[self window] addSubview:imageView];
return YES;
}
将以下内容添加到Utility.h
+ (NSString *)getBackgroundImageNameWithOrientation:(UIDeviceOrientation)interfaceOrientation;
将以下内容添加到Utility.m
+ (NSString *)getBackgroundImageNameWithOrientation:(UIDeviceOrientation)interfaceOrientation
{
NSString *imageName = nil;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
{
if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
{
imageName = @"Default-Landscape~ipad.png";
}
else
{
imageName = @"Default-Portrait~ipad.png";
}
}
else
{
if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
{
imageName = @"Default-Landscape~iphone.png";
}
else
{
imageName = @"Default.png";
}
}
return imageName;
}
答案 5 :(得分:0)
iOS7的Windows与iOS8 / 9的Windows有不同的行为。
iOS7的键盘窗口和iOS8 / 9的所有窗口始终具有正确的方向和位置。尺寸。因此,您可以观察大小更改事件并更新视图的框架。
但iOS7的其他窗口始终保持纵向和大小。您需要在轮换后更新视图转换。
您需要观察UIApplicationWillChangeStatusBarOrientationNotification并更新UIView的大小,如下所示:
%>%