I'm in a dilemma which method to use for setting frames of custom UIViews with many subviews in it and still have animations and automatically adjust to rotations. What I usually do when I create a new viewcontroller is alloc my custom view in loadView or viewDidLoad, e.g:

-(void)viewDidLoad
{
    [super viewDidLoad];
    detailView = [[DetailView alloc] initWithFrame:CGRectMake(0, 0,      self.view.frame.size.width, self.view.frame.size.height)];
    detailView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
    self.view = detailView;    
}

Normally this width & height is not correct for an iPhone5-screen (the actual view-frame is not set until viewWillAppear) but because of the autoresizingmask it all works out.

Then in the initWithFrame of the custom UIView DetailView, I alloc all subviews with CGRectZero, e.g:

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        label = [[UILabel alloc] initWithFrame:CGRectZero];
        [self addSubview:label];
    }
 }

Then I override layoutsubviews to set all frames of all subviews. This works perfectly for any screen size and any orientation, e.g:

-(void)layoutSubviews
{
    [super layoutSubviews];
    label.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
}

However, I just found out that layoutSubviews is not so great when you use animations, because when you use animations in an animationblock, layoutsubviews is called in the middle of the animation and it completely breaks the animation, e.g:

-(void)animateLabel
{
    [UIView animateWithDuration:0.4f animations:^
    {
        label.transform = CGAffineTransformMakeTranslation(100, 100);
    }];
}

I believe there are ugly workarounds this by using flags for each animation and in layoutsubviews use those flags to set the correct start or endframe of the animated block but I don't think I should have to create a flag for each animation I want to do.

So my problem is now: how am I supposed to have a custom UIView WITH animations that also automatically adjusts itself to rotations?

The only solution I can come up with right now (that I don't like): Don't use layoutSubviews but use the setFrame/setBounds method of the custom UIView to set the frames of all subviews. Then check in the viewController every time a rotation occurs and then use the setFrame/setBounds method of the custom UIView to change all frames of all subviews. I don't like this solution because the rotation methods are different in iOS5 and iOS6 and I don't want to have to do this in every UIViewController with it's own custom UIView.

Any suggestions?

有帮助吗?

解决方案

I have recently started overriding viewDidLayoutSubviews (many times instead of viewWillAppear) in my UIViewControllers.

Yes viewDidLayoutSubviews is called on rotations. (from comment)

The method fires after all the internal layouts have already been completed so all finalized frames should be setup, but still give you the time you need to make adjustments before the the view is visible and shouldn't have any issues with animations because you are not already inside an animation block.

viewcontroller.m

- (void)viewDidLayoutSubViews {
    // At this point I know if an animation is appropriate or not.
    if (self.shouldRunAnimation)
        [self.fuView runPrettyAnimations];
}

fuView.m

- (void)runPrettyAnimations {
    // My animation blocks for whatever layout I'd like.
}

- (void)layoutSubviews {
    // My animations are not here, but non animated layout changes are.
    // - Here we have no idea if our view is visible to the user or may appear/disappear
    // partway through an animation.
    // - This also might get called far more than we intend since it gets called on
    // any frame updates.
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top