转换子视图时调用的UIViewController viewDidLayoutSubviews

时间:2014-08-22 20:25:25

标签: objective-c uiview ios7

我有以下用例:

  • 一个视图控制器(RotationVC),其中包含一些逻辑,其中包括旋转其中一个子视图(通过将其转换设置为CGAffineTransformMakeRotation)
  • 此RotationVC会覆盖viewDidLayoutSubviews方法,以将其子视图设置为与父视图一样大(self.view) (创建视图控制器及其视图都是以编程方式完成的,必须保持这种方式;我尝试在子视图上使用具有灵活宽度和灵活高度的autoresizingMask但它没有工作)< / LI>
  • 另一个视图控制器(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 个答案:

答案 0 :(得分: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属性不是identity变换,则该视图的frame属性的值是未定义的,必须忽略。将变换应用于视图时,必须使用视图的边界和中心属性来获取视图的大小和位置。任何子视图的框架矩形仍然有效,因为它们相对于视图的边界。

我一直认为设置框架同时设置边界和中心,但显然这是非常不真实的。