转换子视图时调用的 UIViewController viewDidLayoutSubviews
Posted
技术标签:
【中文标题】转换子视图时调用的 UIViewController viewDidLayoutSubviews【英文标题】:UIViewController viewDidLayoutSubviews called when transforming a subview 【发布时间】:2014-08-22 20:25:24 【问题描述】:我有以下用例:
一个视图控制器 (RotationVC),其中包含一些逻辑,其中包括旋转其中一个子视图(通过将其转换设置为 CGAffineTransformMakeRotation) 此 RotationVC 覆盖 viewDidLayoutSubviews 方法以将其子视图设置为与父视图 (self.view) 一样大 (创建视图控制器及其视图都是以编程方式完成的,它必须保持这种方式;我尝试在子视图上使用具有灵活宽度和灵活高度的 autoresizingMask,但它不起作用) 另一个视图控制器 (ParentVC) 将 RotationVC 添加为其子视图,将其视图添加为其子视图,并将其框架在某个点设置为方形 - 想法是,当设置框架时,将调用并设置 RotationVC viewDidLayoutSubviews子视图以正确大小(实际上工作正常),然后一切正常 (RotationVC 也将在其他视图控制器中使用,并且具有不同的大小,这就是它被提取到“子”视图控制器的原因,并且它的大小应该是灵活的)嗯,它不能正常工作。问题是每次旋转后,都会调用 RotationVC viewDidLayoutSubviews 方法,该方法设置旋转后的视图框架。这是错误的,根据 Apple 的文档,当视图的转换不是身份时(在这种情况下),使用 frame 属性是错误的。结果,旋转的视图是“倾斜的”。这是委托的源代码,您应该能够将其粘贴到单个文件并运行。如果你这样做了,我想要实现的是让旋转的子视图保持它的形状(在这个例子中它是一个矩形):
#import "AppDelegate.h"
@interface RotationVC : UIViewController
@property (nonatomic, weak) UIView *background;
@property (nonatomic, weak) UIView *foreground;
@property (nonatomic) int degrees;
@end
static const double DURATION = 0.5;
@implementation RotationVC
- (void)viewDidLoad
[super viewDidLoad];
UIView *tmp = [UIView new];
self.background = tmp;
self.background.layer.borderWidth = 2;
self.background.layer.borderColor = [UIColor redColor].CGColor;
[self.view addSubview:self.background];
tmp = [UIView new];
self.foreground = tmp;
self.foreground.layer.borderWidth = 2;
self.foreground.layer.borderColor = [UIColor blueColor].CGColor;
[self.view addSubview:self.foreground];
- (void)viewDidLayoutSubviews
[super viewDidLayoutSubviews];
self.background.frame = self.view.bounds;
CGAffineTransform tmp = self.foreground.transform;
self.foreground.transform = CGAffineTransformIdentity;
self.foreground.frame = self.view.bounds;
self.foreground.transform = tmp;
- (void)viewWillAppear:(BOOL)animated
[super viewWillAppear:animated];
[self performSelector:@selector(rotate) withObject:self];
- (void)rotate
self.degrees = (self.degrees + 15) % 360;
[UIView animateWithDuration:DURATION
delay:0
options:UIViewAnimationOptionCurveLinear|UIViewAnimationOptionBeginFromCurrentState
animations:^
self.foreground.transform = CGAffineTransformMakeRotation(self.degrees * M_PI/180);
completion:^(BOOL finished)
[self performSelector:_cmd withObject:self afterDelay:0];
];
@end
@interface ParentVC : UIViewController
@property (nonatomic, weak) RotationVC *rotationVC;
@end
@implementation ParentVC
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
RotationVC *tmp = [RotationVC new];
self.rotationVC = tmp;
[self addChildViewController:self.rotationVC];
[self.rotationVC didMoveToParentViewController:self];
return self;
- (void)viewDidLoad
[super viewDidLoad];
[self.view addSubview:self.rotationVC.view];
- (void)viewWillAppear:(BOOL)animated
[super viewWillAppear:animated];
self.rotationVC.view.bounds = CGRectMake(0, 0, 100, 100);
self.rotationVC.view.center = self.view.center;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:[ParentVC new]];
navi.navigationBarHidden = YES;
self.window.rootViewController = navi;
[self.window makeKeyAndVisible];
return YES;
@end
有一个有效的技巧 - 在 viewDidLayoutSubviews 方法中,将旋转视图的变换存储到临时变量,将视图的变换设置为标识,设置框架,然后再次将其设置为旋转 - 这太丑了,我打赌必须有更好的方法。我还能够设计出其他一些解决方法,但每一个都比前一个更丑……
在这种情况下,有没有人知道该怎么做?
【问题讨论】:
【参考方案1】:我能够解决这个问题。只需使用以下代码:
self.foreground.bounds = self.view.bounds;
self.foreground.center = self.background.center;
而不是设置框架。
这在https://developer.apple.com/library/ios/documentation/windowsviews/conceptual/viewpg_iphoneos/WindowsandViews/WindowsandViews.html#//apple_ref/doc/uid/TP40009503-CH2-SW7中有解释:
重要提示:如果视图的 transform 属性不是恒等变换,则该视图的 frame 属性的值是未定义的,必须被忽略。将变换应用于视图时,必须使用视图的边界和中心属性来获取视图的大小和位置。任何子视图的框架矩形仍然有效,因为它们是相对于视图边界的。
我一直以为设置frame就是同时设置bounds和center,但显然这很不正确。
【讨论】:
以上是关于转换子视图时调用的 UIViewController viewDidLayoutSubviews的主要内容,如果未能解决你的问题,请参考以下文章
显示和隐藏 uisearchcontroller 时调用的函数
当我的 UIViewController 被弹出时调用的方法?
iOS 生命周期 -initviewDidLoadviewWillAppearviewDidAppearviewWillDisappearviewDidDisappear 区别和用途