The problem is NOT the auto-layout constraints...
The issue is that setting the frame of a subview in [UIView animateWithDuration:...] triggers a call to layoutSubviews ... where you again set the frame of the subview.
To avoid that, we can add a CGRect property to track self.bounds and, in layoutSubviews, only update _imageView.frame if self.bounds has changed.
Example code...
MyView.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface MyView : UIView
-(void)animateOnImage;
@end
NS_ASSUME_NONNULL_END
MyView.m
#import "MyView.h"
@implementation MyView
{
UIView *_imageView;
CGRect myBounds;
}
- (instancetype)init
{
self = [super init];
if (self) {
_imageView = [UIView new];
_imageView.backgroundColor = UIColor.blueColor;
[self addSubview:_imageView];
myBounds = CGRectZero;
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
// debug - log that layoutSubviews was called
NSLog(@"layoutSubviews");
// only execute the following if self.bounds has changed
if (!CGRectEqualToRect(myBounds, self.bounds)) {
// debug - log that self.bounds has changed
NSLog(@"self.bounds changed, so set _imageView frame");
myBounds = self.bounds;
_imageView.frame = self.bounds;
}
}
-(void)animateOnImage {
[UIView animateWithDuration:2 animations:^{
[self shrinkImageView];
}];
}
- (void)shrinkImageView {
_imageView.frame = CGRectMake(50, 100, 150, 200);
_imageView.alpha = 0.5;
}
@end
AnimSubViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface AnimSubViewController : UIViewController
@end
NS_ASSUME_NONNULL_END
AnimSubViewController.m
#import <UIKit/UIKit.h>
#import "AnimSubViewController.h"
#import "MyView.h"
@interface AnimSubViewController ()
{
MyView *myView;
}
@end
@implementation AnimSubViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.systemBackgroundColor;
myView = [MyView new];
myView.backgroundColor = UIColor.systemYellowColor;
myView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:myView];
UILayoutGuide *g = self.view.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
[myView.topAnchor constraintEqualToAnchor:g.topAnchor constant:120.0],
[myView.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:80.0],
[myView.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:-80.0],
[myView.bottomAnchor constraintEqualToAnchor:g.bottomAnchor constant:-120.0],
]];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(animateView) userInfo:nil repeats:NO];
}
- (void)animateView
{
[myView animateOnImage];
}
@end
