1

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:

  • Subclassing the button, but read that I shouldn't do that
  • Animating the border (while subclassed), but the border only goes inwards, so it seems like I need to animate the frame too

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

Community
  • 1
  • 1
smileham
  • 1,430
  • 2
  • 16
  • 28
  • have you tried setting your button.clipToBounds = false. This will allow your border to grow past the bounds of the button and not only inwards – Julio Apr 12 '16 at 18:14
  • That would only work on subviews, so it doesn't work on a button subclass, correct? – smileham Apr 12 '16 at 18:20
  • No, it should work on the button subclass as well. Anything that inherits the UIView class can call clipsToBounds. See https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIButton_Class/ – Julio Apr 12 '16 at 19:04

1 Answers1

1

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.

Jaybit
  • 1,864
  • 1
  • 13
  • 20
  • Thank you so much!!! This really helped me understand how to put it all together, and it's working now, so thank you :D – smileham Apr 14 '16 at 05:11