I have a UIView shaped like a circle that expands and contracts. I need to have a sublayer positioned at its center that stays the same size as it is animating. The code below contains four sample views showing things I have tried. It can be copied and pasted as is.
@"bounds"
and one for @"cornerRadius"
. This arrangement causes the sublayer to end up at the screen's origin (top left).@"bounds.size"
and @"cornerRadius"
. The sublayer stays the same size, which is good, but it does not stay at the center of the UIView. I tried to use [thirdView.layer setNeedsDisplayOnBoundsChange:YES];
to compensate for the bounds change but it didn't work. I also tried thirdView.contentMode = UIViewContentModeRedraw;
.@"transform.scale"
, which seems to be a bit more efficient as far as expansion animations go. The sublayer stays at the center of the UIView like I want it, but it does not stay the same size. I need to have the size of the sublayer be independent because I intend to animate it.Here's all the code. It looks like a lot but it's some pretty simple stuff.
- (void)viewDidLoad {
[super viewDidLoad];
float screenWidth = [UIScreen mainScreen].bounds.size.width;
float screenHeight = [UIScreen mainScreen].bounds.size.height;
UIView * firstView = [[UIView alloc] initWithFrame:CGRectMake((screenWidth/4) - 25, (screenHeight/4) - 25, 50, 50)];
// [firstView.layer setAnchorPoint:CGPointMake(0.5, 0.5)];
firstView.backgroundColor = [UIColor blueColor];
firstView.layer.cornerRadius = 25;
NSLog(@"firstView anchor point %@", [NSValue valueWithCGPoint:firstView.layer.anchorPoint]);
CALayer * firstLayer = [CALayer layer];
firstLayer.backgroundColor = [UIColor redColor].CGColor;
[firstView.layer addSublayer:firstLayer];
firstLayer.bounds = CGRectMake(0,0, 30, 30);
firstLayer.cornerRadius = 15;
firstLayer.position = CGPointMake(firstView.bounds.size.width/2, firstView.bounds.size.height/2);
[self.view addSubview:firstView];
UIView * secondView = [[UIView alloc] initWithFrame:CGRectMake((screenWidth*3/4) - 25, (screenHeight/4) - 25, 50, 50)];
secondView.backgroundColor = [UIColor blueColor];
secondView.layer.cornerRadius = 25;
CALayer * secondLayer = [CALayer layer];
secondLayer.backgroundColor = [UIColor redColor].CGColor;
[secondView.layer addSublayer:secondLayer];
secondLayer.bounds = CGRectMake(0, 0, 30, 30);
secondLayer.cornerRadius = 15;
secondLayer.position = CGPointMake(secondView.bounds.size.width/2, secondView.bounds.size.height/2);
CABasicAnimation * secondViewBoundsAnimation;
secondViewBoundsAnimation = [CABasicAnimation animation];
secondViewBoundsAnimation.keyPath = @"bounds";
secondViewBoundsAnimation.fromValue = [NSValue valueWithCGRect:CGRectMake((screenWidth*3/4) - 25, (screenHeight/4) - 25, 50, 50)];
secondViewBoundsAnimation.toValue = [NSValue valueWithCGRect:CGRectMake((screenWidth*3/4) - 50, (screenHeight/4) - 50, 100, 100)];
CABasicAnimation * secondViewCornerRadiusAnimation;
secondViewCornerRadiusAnimation = [CABasicAnimation animation];
secondViewCornerRadiusAnimation.keyPath = @"cornerRadius";
secondViewCornerRadiusAnimation.fromValue = @25;
secondViewCornerRadiusAnimation.toValue = @50;
CAAnimationGroup * secondViewAnimationGroup;
secondViewAnimationGroup = [CAAnimationGroup animation];
secondViewAnimationGroup.animations = [NSArray arrayWithObjects:secondViewBoundsAnimation, secondViewCornerRadiusAnimation, nil];
secondViewAnimationGroup.duration = 1.5;
secondViewAnimationGroup.repeatCount = HUGE_VALF;
secondViewAnimationGroup.autoreverses = YES;
[secondView.layer addAnimation:secondViewAnimationGroup forKey:@"secondViewAnimation"];
[self.view addSubview:secondView];
UIView * thirdView;
// [thirdView.layer setAnchorPoint:CGPointMake(0.5, 0.5)];
thirdView = [[UIView alloc] initWithFrame:CGRectMake((screenWidth/4) - 25, (screenHeight*3/4) -25, 50, 50)];
thirdView.backgroundColor = [UIColor blueColor];
thirdView.layer.cornerRadius = 25;
NSLog(@"thirdView anchor point %@", [NSValue valueWithCGPoint:thirdView.layer.anchorPoint]);
CALayer * thirdLayer = [CALayer layer];
thirdLayer.backgroundColor = [UIColor redColor].CGColor;
[thirdView.layer addSublayer:thirdLayer];
thirdLayer.bounds = CGRectMake(0, 0, 30, 30);
thirdLayer.cornerRadius = 15;
thirdLayer.position = CGPointMake(thirdView.bounds.size.width/2, thirdView.bounds.size.height/2);
CABasicAnimation * thirdViewSizeAnimation;
thirdViewSizeAnimation = [CABasicAnimation animation];
thirdViewSizeAnimation.keyPath = @"bounds.size";
thirdViewSizeAnimation.fromValue = [NSValue valueWithCGSize:CGSizeMake(50, 50)];
thirdViewSizeAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(100, 100)];
CABasicAnimation * thirdViewCornerRadiusAnimation;
thirdViewCornerRadiusAnimation = [CABasicAnimation animation];
thirdViewCornerRadiusAnimation.keyPath = @"cornerRadius";
thirdViewCornerRadiusAnimation.fromValue = @25;
thirdViewCornerRadiusAnimation.toValue = @50;
CAAnimationGroup * thirdViewAnimationGroup;
thirdViewAnimationGroup = [CAAnimationGroup animation];
thirdViewAnimationGroup.animations = [NSArray arrayWithObjects:thirdViewSizeAnimation, thirdViewCornerRadiusAnimation, nil];
thirdViewAnimationGroup.duration = 1.5;
thirdViewAnimationGroup.repeatCount = HUGE_VALF;
thirdViewAnimationGroup.autoreverses = YES;
// thirdView.contentMode = UIViewContentModeRedraw;
// [thirdView.layer setNeedsDisplayOnBoundsChange:YES];
[thirdView.layer addAnimation:thirdViewAnimationGroup forKey:@"thirdViewAnimation"];
[self.view addSubview:thirdView];
UIView * fourthView = [[UIView alloc] initWithFrame:CGRectMake((screenWidth*3/4) - 25, (screenHeight*3/4) - 25, 50, 50)];
fourthView.backgroundColor = [UIColor blueColor];
fourthView.layer.cornerRadius = 25;
CALayer * fourthLayer = [CALayer layer];
fourthLayer.backgroundColor = [UIColor redColor].CGColor;
[fourthView.layer addSublayer:fourthLayer];
fourthLayer.bounds = CGRectMake(0, 0, 30, 30);
fourthLayer.cornerRadius = 15;
fourthLayer.position = CGPointMake(fourthView.bounds.size.width/2, fourthView.bounds.size.height/2);
CABasicAnimation * fourthViewScaleAnimation;
fourthViewScaleAnimation = [CABasicAnimation animation];
fourthViewScaleAnimation.keyPath = @"transform.scale";
fourthViewScaleAnimation.fromValue = @1;
fourthViewScaleAnimation.toValue = @2;
fourthViewScaleAnimation.duration = 1.5;
fourthViewScaleAnimation.repeatCount = HUGE_VALF;
fourthViewScaleAnimation.autoreverses = YES;
[fourthView.layer addAnimation:fourthViewScaleAnimation forKey:@"fourthViewAnimation"];
[self.view addSubview:fourthView];
Since changing the origin of the UIView isn't possible, I need to find out a way to do either one of these things:
I can't do multiple UIViews because I intend to add the entire layer to an MKAnnotationView.
Thanks!
I figured out a solution and I feel stupid that I didn't think of it immediately. I can use two layers. The UIView does't change size. One layer expands and contracts, and another layer on top of it stays in the same position since the UIView isn't moving.