Is there an iOS method that fires when Autolayout

2020-03-01 07:05发布

问题:

I have an iOS app in which I need to know when a new view is completely visible on-screen; that is, when Autolayout has finished its calculations and the view has finished drawing.

ViewDidAppear seems to fire well before the view is completely visible. If I turn off Autolayout, the timing seems to line up as far as human perception goes, but I need to use Autolayout in this project (so this isn't a solution...just a test).

Is there any method that fires when Autolayout is done calculating? Or another method that fires when the view is ACTUALLY visible (since ViewDidAppear doesn't work for this)?

Thanks!

回答1:

I'm using viewDidLayoutSubviews for this. Apple's documentation says, "Called to notify the view controller that its view has just laid out its subviews."



回答2:

The following can be used to avoid multiple calls:

- (void) didFinishAutoLayout {

    // Do some stuff here.    

    NSLog(@"didFinishAutoLayout");
}

and

- (void) viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];


    [NSObject cancelPreviousPerformRequestsWithTarget:self
                                 selector:@selector(didFinishAutoLayout)
                                           object:nil];
    [self performSelector:@selector(didFinishAutoLayout) withObject:nil
               afterDelay:0];
}


回答3:

What it worked in my case was request layout after changed a constraint value:

    self.cnsTableviewHeight.constant = 50;
    [self layoutIfNeeded];

Later on override layoutSubviews method:

    - (void) layoutSubviews { //This method when auto layout engine finishes
    }

You can call setNeedsLayout also instead of layoutIfNeeded



回答4:

I guess implementing viewDidLayoutSubviews is the correct way but I used an animation just to write the completion callback inside the same method.

someConstraint.constant = 100; // the change

// Animate just to make sure the constraint change is fully applied
[UIView animateWithDuration:0.1f animations:^{
    [self.view setNeedsLayout];
} completion:^(BOOL finished) {
    // Here do whatever you need to do after constraint change
}];


回答5:

You might face this problem not just with UIViewControllers but also UIViews. If you have a subview and want to know if AutoLayout has updated it's bounds, here is the Swift 5 implementation,

var viewBounds: CGFloat = 0.0
var autoLayoutHasCompleted: Bool = false

override func awakeFromNib() {
    super.awakeFromNib()

    // someSubView is the name of a view you want to check has changed
    viewBounds = someSubView.bounds.width 
}    

override func layoutSubviews() {
    if viewBounds != someSubView.bounds.width && !autoLayoutHasCompleted {
        // Place your code here
        autoLayoutHasCompleted = true
    }
}