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 CAShapeLayer,but first I had to create a CGPath for each of the threestrokes.

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 aUIBezierPath. I then rewrote said piece of code into the followinginstructions that create the desired CGPath object:

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 CGPaths straight from SVGfiles,but for a short path like this one,having it in code is not a big deal.

In my UIButton subclass,I added three CAShapeLayer properties and set thetheir paths accordingly:

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,CGPathCreatecopyByStrokingPath will create apath that follows the outlines of the original stroke,therefore its boundingBox will then fully contain the contents of the CAShapeLayer:

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 anchorPoint accordingly when layouting their layers:

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 CAShapeLayer’s strokeStart and strokeEndproperties separately.

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:

How to build a nice Hamburger Button transition in Swift的更多相关文章

  1. HTML实现代码雨源码及效果示例

    这篇文章主要介绍了HTML实现代码雨源码及效果示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  2. 吃透移动端 1px的具体用法

    这篇文章主要介绍了吃透移动端 1px的具体用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  3. html5开发三八女王节表白神器

    一年一度的三八女王节马上来临,今天小编基于html5给大家开发一个表白神器,做一个 浪漫的程序猿,具体代码大家参考下本文

  4. html5实现图片转圈的动画效果——让页面动起来

    这篇文章主要介绍了html5实现图片转圈的动画效果——让页面动起来的相关资料,需要的朋友可以参考下

  5. HTML5 3D书本翻页动画的实现示例

    这是一款十分炫酷的HTML5 3D书本翻页动画,效果相对比较简单,拖拽鼠标模拟用手翻页,需要的朋友们下面随着小编来一起学习学习吧

  6. html5简介及新增功能介绍

    这篇文章主要介绍了html5简介及新增功能介绍,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  7. HTML5 图片悬停放大的实现代码示例

    这篇文章主要介绍了HTML5 图片悬停放大的实现代码示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  8. ios – 相机图像旋转问题

    我在这里遇到一个非常奇怪的问题.当我以纵向模式单击图像并上传它然后再次获取它时,显示逆时针旋转90度.但是当我在相机胶卷中看到它时,它会以正确的方向显示.我已经尝试了几乎所有可能的链接/代码来解决这个问题,但似乎没有任何帮助.我以JPEG格式保存图像.请帮助这个人.提前致谢!!解决方法解决方法是在UIImage上创建一个类别,并根据其元数据EXIF缩放和旋转图像.这是一段神奇的代码:

  9. 如何在iOS上生成带有“真实”文本内容的PDF?

    我想在iOS6应用程序中生成一个好看的PDF.我试过了:>UIView在上下文中渲染>使用CoreText>使用NsstringdrawInRect>使用UILabeldrawRect这是一个代码示例:呈现的UIViews只包含UIImageView一堆UILabel.我还尝试了在stackoverflow上找到的建议:继承UILabel并执行此操作:但这也没有改变任何事情.无论我做什么,当在预览中打开PDF时,文本部分可以选择作为块,但不是每个字符的字符,并且缩放pdf显示它实际上是位图图像.有什么建议

  10. 内存警告UIImagepickerController IOS 7

    任何人都可以帮助我解决这个问题,我对客观的c和iOS有点新鲜.我一直在努力,但我无法弄清楚如何解决问题,我的应用程序非常简单,只有启动相机拍照并通过电子邮件发送到我们的服务器.这个代码在iOS6中工作得很好.当我拍照时,我的内存是每个屏幕捕获的堆增长,我得到“收到内存警告”,最后–由于内存压力而终止.–可能是内存管理.我会感谢你的帮助解决方法您使用fixRotation方法处于正确的轨道.但是,您

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部