smileham
smileham

Reputation: 1460

How do I create a growing iOS Button?

My friend gave me the following designs for iOS buttons, and I'm not sure the best way to implement this.

I need to make the reusable button shown below (in Objective-C).

I've tried:

So how do I approach this? I'm assuming making a CustomButtonView class which has a button (composition) as well as an inner and outer circle view? How would I then animate that to grow? Would I have to animate the frame change too, or could I use insets?

What is the simplest code to make this work? Thanks!

Growing Buttons

Upvotes: 1

Views: 117

Answers (1)

Jaybit
Jaybit

Reputation: 1864

Here Is the approach I took to create this:

ButtonAnimation

  1. Subclass UIView to create your custom button
  2. Use UITapGestureRecognizer or touchesBegan, touchesEnded... for your interaction
  3. Add two CALayer's for your foreground and background layers
  4. Add your icon layer (This can be an UIImageView or any other way of displaying an image)

    - (id)initWithIcon:(UIImage *)icon backgroundColor:(UIColor *)backgroundColor foregroundColor:(UIColor *)foregroundColor {
    
        if (self = [super init]) {
            // Background Layer Setup
            _backgroundLayer = [CALayer new];
            [_backgroundLayer setBackgroundColor:backgroundColor.CGColor];
            [self.layer addSublayer:_backgroundLayer];
    
            // Foreground Layer Setup
            _foregroundLayer = [CALayer new];
            [_foregroundLayer setBackgroundColor:foregroundColor.CGColor];
            [self.layer addSublayer:_foregroundLayer];
    
            // Icon Setup
            _icon = [[UIImageView alloc] initWithImage:icon];
            [_icon setContentMode:UIViewContentModeCenter];
            [self addSubview:_icon];
    
            UIGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(buttonTapped:)];
            [self addGestureRecognizer:tapGesture];
        }
        return self;
    }
    
    - (void)setFrame:(CGRect)frame {
    
        // Make sure super is called
        [super setFrame:frame];
    
        // Build the layout of backgroundLayer
        [self.backgroundLayer setFrame:CGRectMake(frame.size.width*0.1, frame.size.width*0.1, frame.size.width*0.8, frame.size.width*0.8)];
        [self.backgroundLayer setCornerRadius:frame.size.width*0.8/2];
    
        // Build the layout of forgroundLayer
        [self.foregroundLayer setFrame:CGRectMake(frame.size.width*0.05, frame.size.width*0.05, frame.size.width*0.9, frame.size.width*0.9)];
        [self.foregroundLayer setCornerRadius:frame.size.width*0.9/2];
    
        // Build the frame of your icon
        [self.icon setFrame:CGRectMake(0, 0, frame.size.width, frame.size.width)];
    }
    
    - (void)buttonTapped:(UIGestureRecognizer*)gesture {
    
        // Animate the foreground getting smaller
        CABasicAnimation *foregroundFrameChange = [CABasicAnimation animationWithKeyPath:@"frame"];
        foregroundFrameChange.fromValue = [NSValue valueWithCGRect:_foregroundLayer.frame];
        foregroundFrameChange.toValue   = [NSValue valueWithCGRect:CGRectMake(self.frame.size.width*0.1,self.frame.size.width*0.1, self.frame.size.width*0.8, self.frame.size.width*0.8)];
        self.foregroundLayer.frame = CGRectMake(self.frame.size.width*0.1,self.frame.size.width*0.1, self.frame.size.width*0.8, self.frame.size.width*0.8);
    
        // Animate the forground cornerRadius to stay rounded
        CABasicAnimation *foregroundRadiusChange = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
        foregroundRadiusChange.fromValue = [NSNumber numberWithDouble:self.foregroundLayer.cornerRadius];
        foregroundRadiusChange.toValue   = [NSNumber numberWithDouble:self.frame.size.width*0.8/2];
        [self.foregroundLayer setCornerRadius:self.frame.size.width*0.8/2];
    
        // Animate the background getting larger
        CABasicAnimation *backgroundFrameChange = [CABasicAnimation animationWithKeyPath:@"frame"];
        backgroundFrameChange.fromValue = [NSValue valueWithCGRect:self.backgroundLayer.frame];
        backgroundFrameChange.toValue   = [NSValue valueWithCGRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.width)];
        self.backgroundLayer.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.width);
    
        // Animate the background cornerRadius to stay rounded
        CABasicAnimation *backgroundRadiusChange = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
        backgroundRadiusChange.fromValue = [NSNumber numberWithDouble:self.backgroundLayer.cornerRadius];
        backgroundRadiusChange.toValue   = [NSNumber numberWithDouble:self.frame.size.width/2];
        [self.backgroundLayer setCornerRadius:self.frame.size.width/2];
    
        // Group all the animations to run simultaneously
        CAAnimationGroup *allAnimations = [CAAnimationGroup animation];
        allAnimations.duration   = 2;
        allAnimations.animations = @[foregroundFrameChange, foregroundRadiusChange, backgroundFrameChange, backgroundRadiusChange];
        allAnimations.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        [self.layer addAnimation:allAnimations forKey:@"animate"];
    
        // Create your button action callback here
    }
    

    This was a quick mock up and not a complete solution but it will give you something to play with.

Upvotes: 1

Related Questions