cannot update view.layer.frame in viewDidLoad?

前端 未结 5 1883
予麋鹿
予麋鹿 2021-02-19 18:59

I am trying to execute following code in viewDidLoad method of my single view controller project:

self.view.layer.frame = CGRectInset(self.view.layer.frame, 20,          


        
相关标签:
5条回答
  • 2021-02-19 19:37

    Rob Mayoff's answer is correct and excellent, but putting it a slightly different way: viewDidLoad only means the view has loaded, i.e. that the view controller has obtained its view. It doesn't mean that the view has been placed in the interface. That, indeed, is one of the things that viewDidAppear: does mean — and that's why it worked when you ran your code there.

    The trick in this sort of situation, where you want to initialize something about the view, is to do it late enough but do it only once. viewDidAppear: could easily be called again later, but you don't want to initialize the view again (unless it has been unloaded). In iOS 5, isMovingToParentViewController allows you to distinguish the particular circumstances you're looking for. Before that, it might be necessary to set up a BOOL flag so that you perform final initializations only once.

    A related trap is what happens when the app launches into landscape orientation. Here, too, viewDidLoad is too soon because the interface has not yet rotated into landscape.

    However, this issue should not be arising at all. It should be none of your business to inset a view controller's view. Either the view is the root view controller, in which case its size is correctly taken care of automatically, or it is the child of a parent view controller, in which case it is the parent view controller's job to size the view (as UINavigationController, for example, already does), or the view is to be presented modally, in which case its size will be set automatically to match the view it replaces. So I would suggest that you very question suggests you're doing something wrong.

    0 讨论(0)
  • 2021-02-19 19:44

    Create your project with an older version of Xcode (for instance I'm using Xcode 4.3.3 for this) . Then you can use setFrame: method with viewDidLoad in any version of Xcode .

    0 讨论(0)
  • 2021-02-19 19:45

    The viewDidLoad method is too early to set your view's frame because something else is changing the frame later.

    For example, if this is your root view controller, then the UIWindow object will set the view's frame when it adds the view to itself as a subview. The viewDidLoad method runs as soon as loadView returns, before any outside object (like the UIWindow) can get its hands on the view.

    You can test this by using a custom view (if you're not already) and overriding setFrame: in the custom view class:

    - (void)setFrame:(CGRect)frame {
        [super setFrame:frame];
    }
    

    Put a breakpoint in that method and you'll see that the view's frame gets set some time after viewDidLoad returns.

    0 讨论(0)
  • 2021-02-19 19:51

    I also experienced this issue on Ray Wenderlich's tutorial 'Introduction to CALayers'. http://www.raywenderlich.com/2502/introduction-to-calayers-tutorial

    It seems shrinking the entire view controllers view is not the best thing to do. Instead create a sub view and call CGRectInset on that e.g in your view controllers viewDidLoad

    UIView *viewToManipulate = [[UIView alloc] initWithFrame:CGRectMake(0.0,0.0, self.view.bounds.size.width, self.view.bounds.size.height)];
    
    [self.view addSubview:viewToManipulate];
    
    viewToManipulate.backgroundColor = [UIColor redColor];
    viewToManipulate.layer.cornerRadius = 20.0;
    viewToManipulate.layer.frame = CGRectInset(self.view.layer.frame, 20, 20);
    
    0 讨论(0)
  • 2021-02-19 20:00

    I think the issue you are running into with this line:

    self.view.layer.frame = CGRectInset(self.view.layer.frame, 20, 20);
    

    can be explained like so :

    • in viewDidLoad, the properties are set, but the frame of the views are not yet defined.
    • by the time viewWillAppear is triggered, they will be set. That explains why that line of code works there.
    • But since iOS 5, there is another method called after viewDidLoad and before viewWillAppear in which the view frames are set : viewDidLayoutSubviews.

    You can find the complete explanation of this in this season's Stanford CS193P course about iOS programming (very cool by the way).

    So if you want it to work just once, use :

    - (void)viewDidLayoutSubviews
    {
        self.view.layer.frame = CGRectInset(self.view.layer.frame, 20, 20);
    }
    

    PS : I posted this answer on Ray's forum too. Regards, Fred

    0 讨论(0)
提交回复
热议问题