0

I am trying to animate UITabBar items by using a UIImageView and setting its frame in the same frame as my UITabBarItem's when the view first renders to the user. In a different project, it works fine on viewDidAppear, logs showing that the frame is in the same frame as the one in my original project (I have 5 items, and the 5th item is always at 333, 1). On my original project, viewDidAppear will return 0, 0 and returns 333, 1 on viewDidLayoutSubviews. I moved the code to animate on viewDidLayoutSubviews and discovered that it gets called twice, and returns 2 values, 0, 0 on the first call, and 333, 1 on the second call.

Is there a way to start the animation after viewDidLayoutSubviews is finished with the second call?

I have tried moving around the animation code in viewWillAppear, viewDidAppear, and viewDidLayoutSubviews.

viewWillAppear and viewDidAppear resulted in the converted CGPoint as the original CGPoint of the tab bar (0, 617).

viewDidLayoutSubviews resulted in the converted CGPoint as the new CGPoint of the Tab Bar (0, 687) on the first call and starts the animation, and the actual frame after the animation is finished on the second call.

The following code is what I have on my viewDidLayoutSubviews:

-(void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    if(self.fromTabBar) {
        NSInteger index = 5;
        UIImageView *imageView = [[self.tabBar.subviews  lastObject].subviews firstObject];
        [self startAnimation:imageView withTag:index];
    }
}

The following code is for startAnimation:withTag: :

-(void)startAnimation:(UIImageView *)imageView withTag:(NSInteger)tag {

    CGPoint point = [imageView.superview convertPoint:imageView.frame.origin toView:self.view];

    UIImageView *hexagon = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"vector-profile"]];

    [hexagon setFrame:CGRectMake(point.x, point.y,     imageView.frame.size.width, imageView.frame.size.height)];

    hexagon.alpha = 0;

    [self.view addSubview:hexagon];

    [UIView animateWithDuration:0.5 animations:^{
        imageView.transform = CGAffineTransformMakeScale(0.45, 0.45);
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:0.5 animations:^{
            imageView.alpha = 0;
            hexagon.alpha = 1;
        } completion:nil];
    }];
}

the tag parameter is no longer being used in this method.

I expect the output UIImage to be on top of where the intended UITabBarItem image is (In this case, the 5th position in a UITabBar). This has worked on a different project, but my current project seems to process the rendering differently.

  • What's the actual question though? Read through everything and still don't get what you are trying to ask? `viewDidLayoutSubviews ` got called twice is correct. – Tj3n Jun 25 '19 at 02:34
  • I've edited my post to include my question. My current problem is I want to render/run the animation after viewDidLayoutSubviews is finished getting called the second time so that the UIImageView that I instantiate uses the proper CGRect and is using the proper converted CGPoint – Job Mendoza Jun 25 '19 at 02:44
  • Well nothing you can do about the function got called twice, I suggest you create the `hexagon ` view in `viewDidLoad` as an variable and add it to main view, change it's frame in `viewDidLayoutSubviews ` and call the animation code, if the animation went wrong, try move only the animation code to `viewWillAppear` – Tj3n Jun 25 '19 at 02:52
  • Anything that depends on counting how many times `viewDidLayoutSubviews` is called is wrong-headed. It can be called thousands of times; you should not put code into it that depends on which call this is, except perhaps the very first call (I do that quite a lot, actually). This is a Bad Smell, suggesting you are slotting your code into wrong event. – matt Jun 25 '19 at 02:52

0 Answers0