How to build a nice Hamburger Button transition in Swift
Hamburger buttons may have become somewhat of a cliché in interface designlately,but when I came across a particularly nice transition of ahamburger button on dribbble,I had to try and recreate it in code. Here’s the original shot by the CreativeDash team: You’ll notice how the top and bottom strokes of the hamburger form a X,whilethe middle one morphs into an outline. I knew this effect could be recreatedusing The short,straight strokes can be figured out manually: let shortStroke: CGPath = {
let path = CGPathCreateMutable()
CGPathMoveToPoint(path,nil,2,2)
CGPathAddLineToPoint(path,28,2)
return path
}()
For the middle stroke however,I created a path in Sketch that starts from themiddle and seamlessly transitions into the outline. I then exported this path as an SVG file and imported it into the oldPaintCode 1,which converted the file into a code snippet that created a let outline: CGPath = {
let path = CGPathCreateMutable()
CGPathMoveToPoint(path,10,27)
CGPathAddCurveToPoint(path,12.00,27.00,28.02,40,55.92,50.47,2.00,27,2)
CGPathAddCurveToPoint(path,13.16,40.84,52.00,52)
CGPathAddCurveToPoint(path,52,42.39,27)
return path
}()
There probably is a library that allows you to load In my self.top.path = shortStroke
self.middle.path = outline
self.bottom.path = shortStroke
Then I styled all three of them like so: layer.fillColor = nil
layer.strokeColor = UIColor.whiteColor().CGColor
layer.lineWidth = 4
layer.miterLimit = 4
layer.lineCap = kCALineCapRound
layer.masksToBounds = true
In order to calculate their bounds correctly,I needed take the size of thestroke into account. Thankfully, let boundingPath = CGPathCreateCopyByStrokingPath(layer.path,4,kCGLineCapRound,kCGLineJoinMiter,4)
layer.bounds = CGPathGetPathBoundingBox(boundingPath)
Since the outer strokes will later rotate around their right-most point,I hadto set their self.top.anchorPoint = CGPointMake(28.0 / 30.0,0.5)
self.top.position = CGPointMake(40,18)
self.middle.position = CGPointMake(27,27)
self.middle.strokeStart = hamburgerStrokeStart
self.middle.strokeEnd = hamburgerStrokeEnd
self.bottom.anchorPoint = CGPointMake(28.0 / 30.0,0.5)
self.bottom.position = CGPointMake(40,36)
Now,when the button changes state,it should animate the three strokes to theirnew positions. Once again,the two outer strokes are easy. For the top stroke,Ifirst moved it inward by 4 points to keep in centered,then rotated it bynegative 45 degrees to form one half of the X: var transform = CATransform3DIdentity
transform = CATransform3DTranslate(transform,-4,0)
transform = CATransform3DRotate(transform,-M_PI_4,1)
let animation = CABasicAnimation(keyPath: "transform")
animation.fromValue = NSValue(CATransform3D: CATransform3DIdentity)
animation.toValue = NSValue(CATransform3D: transform)
animation.timingFunction = CAMediaTimingFunction(controlPoints: 0.25,-0.8,0.75,1.85)
animation.beginTime = CACurrentMediaTime() + 0.25
self.top.addAnimation(animation,forKey: "transform")
self.top.transform = transform
(The bottom stroke is left as an exercise to the reader.) Again,the middle stroke is a little trickier. In order to achieve the desiredeffect,I needed to animate the First I had to figure out the correct values for the two properties in the twostates. Note that the even in its hamburger state,the stroke does not start at0. By having the path extend slightly beyond the left edge of the outer strokes,we can achieve a nice anticipation effect when applying the timing functionlater: let menuStrokeStart: CGFloat = 0.325
let menuStrokeEnd: CGFloat = 0.9
let hamburgerStrokeStart: CGFloat = 0.028
let hamburgerStrokeEnd: CGFloat = 0.111
Now we only need to create the animations and add them to the layer: let strokeStart = CABasicAnimation(keyPath: "strokeStart")
strokeStart.fromValue = hamburgerStrokeStart
strokeStart.toValue = menuStrokeStart
strokeStart.duration = 0.5
strokeStart.timingFunction = CAMediaTimingFunction(controlPoints: 0.25,-0.4,0.5,1)
self.middle.addAnimation(strokeStart,forKey: "strokeStart")
self.middle.strokeStart = menuStrokeStart
let strokeEnd = CABasicAnimation(keyPath: "strokeEnd")
strokeEnd.fromValue = hamburgerStrokeEnd
strokeEnd.toValue = menuStrokeEnd
strokeEnd.duration = 0.6
strokeEnd.timingFunction = CAMediaTimingFunction(controlPoints: 0.25,1)
self.middle.addAnimation(strokeEnd,forKey: "strokeEnd")
self.middle.strokeEnd = menuStrokeEnd
Putting everything together,the result looks something like this: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |