Circular UIView from nib with animated and non-ani

2019-07-29 14:27发布

问题:

I'd like to make a custom view that acts just like a UIView when I make bounds, frame, or transform changes: if I change these things with an assignment, the just change in a single frame, if I change them in a UIView animation block, they animate from their current state to the state I set. I'd like to define the view and it's subviews in IB, and set constraints there.

The following code works coming out of the nib with constraints, and successfully sets bounds/frame/transform with assignment (no animation). But I can't get animation working right.

In particular, the animation of the mask layer seems to go wrong. At present (even though I think layoutSubviews should handle it by matching the view animation) the mask jumps by half the view width/height, then animates back into a centered position as the animation proceeds.

@implementation BubbleView

+ (instancetype)bubbleViewFromNib {
    BubbleView *view = [[NSBundle mainBundle] loadNibNamed:@"BubbleView" owner:nil options:nil][0];
    return view;
}

// this works
- (void)setMaskImageName:(NSString *)name {
    self.maskView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:name]];
}

- (void)layoutSubviews {
    [super layoutSubviews];

    // get current animation for bounds
    CAAnimation *anim = [self.layer animationForKey:@"bounds"];

    [CATransaction begin];
    if(anim) {
        // animating, apply same duration and timing function.
        [CATransaction setAnimationDuration:anim.duration];
        [CATransaction setAnimationTimingFunction:anim.timingFunction];

        self.maskView.frame = self.bounds;
    }
    else {
        // not animating, we should disable implicit animations.
        [CATransaction disableActions];
    }

    self.maskView.frame = self.bounds;
    [CATransaction commit];
}
@end

// calling view controller

// the code in this block doesn't work
[UIView animateWithDuration:1 animations:^{
    //b.transform = CGAffineTransformScale(b.transform, 1.4, 1.4);
    b.frame = CGRectInset(b.frame, -30,-30);
}];

// the same code works fine without animation
//b.frame = CGRectInset(b.frame, -30,-30);

I got the layoutSubviews idea from here https://stackoverflow.com/a/25458725/1272965 and with some help from an earlier question I asked here https://stackoverflow.com/a/45356867/1272965 (which was about not animating when changing these props on simple assignment).

Can you help me make my UIView with a mask work like any view provided by iOS, maintaining constraints and changing frame either animated or not animated? Thanks!