第 2 章:设计 COSMOS

原文链接
作者:C4 开源项目
译者:Crystal Sun
全部章节请关注此文集C4教程翻译
校对后的内容请看这里

3月11日,我得了一个机会,可以写一篇教程,发表在知名网站上。所以,我开始和 Jake 讨论一些能够设计、开发、发布的概念,能够抓住 C4 Swift 版本的要点,学习如何使用这个新系统来创建动画...想到:很多基础的动画出现,然后组合成一个优雅的界面,我们看了很多 UI 视频,然后头脑风暴。

Jake 想到了一个点子:

...中间出现了一个实体圆圈,点击后,稍微缩小一下(原来的90%),然后从中心接着放射出八个圆圈,每个圆圈都比之前的圆圈大一点,最外层的圆圈里有不同的图标,点击叉号关闭所有的圆圈,回到初始状态

第 2 章:设计 COSMOS_第1张图片

于是我们看了很多的视频。

讨论概念。

好像行得通。

运行程序。

这就是我们的工作方式。

1. 模拟和测试

实际的应用比较简单,尽管有很多组件,设计交互界面、背景,可能花费一些时间调整,同样的,正是应用还是简单,尽管这些调整比较复杂,不过从创建到完成,这个过程能给我们提供最好的教程素材。

第 2 章:设计 COSMOS_第2张图片

Jake 展示的设计稿只有一个页面,里面有一个炫酷的动画菜单,多层视差背景。我看了一下,思考如何才能让两个组件合并起来。

2. 背景

背景部分的工作比较容易分解,主要就是很多不同内容的图层在按照不同的速度移动。

第 2 章:设计 COSMOS_第3张图片

里面有:

  1. 大星星
  2. 小星星
  3. 连接星星的线
  4. 三个背景星星层
  5. 两个星云层

这完全可以做到,在和 Jake 沟通之后,我写了一个清单列出我需要他定义的一些东西:

  1. 角度/指示器动画
  2. 单个的星座
  3. 三层前景风格 + 运动效果
  4. 三层 星星 背景风格 + 运动效果(incl. # of stars 是什么意思?)
  5. 两层幸运背景风格 + 运动效果

第一步,得到 layer 的数量,同时获取视差角度...需要八个,所以我先用是个来测试一下实际的效果。

本章的代码只是我在真正开发之前的一些测试展示效果,所以当你看完这章后,记得删掉在本章添加的所有代码。

class WorkSpace: CanvasController {
    //创建一个空的数组变量,用来添加 layers
    var layers = [UIScrollView]()

    override func setup() {
        //当 layer 数量小于 10时,执行循环体里的代码
        repeat {
            //创建一个 layer,它的 frame 值和 canvas 的 frame 值一样
            let layer = UIScrollView(frame: view.frame)
            //设置每层 layer 内容的大小,高度为 0 ,防止屏幕垂直滚动
            layer.contentSize = CGSizeMake(layer.frame.size.width * 10, 0)
            //把 layer 添加到 canvas 上以及数组里
            canvas.add(layer)
            layers.append(layer)
        } while layers.count < 10
    }
}

挺简单的吧,使用的工程的文件正是前一章中的,我在 WorkSpace 文件中添加一个 repeat 循环体,来创建新的 layer,添加到 canvas 上,直到创建完 10 layer 为止。每创建一个 layer,我都会把 layer 的 contentSize 设置的超级大(文本中,是 canvas 的二十倍宽)。设置 contentSize 的高度为 0,这样就不会垂直滚动了。

在这时,如果我运行应用,我会什么都看不到,所以我修改一下循环体里代码,给每个 layer 增加一个 label 控件。

class WorkSpace: CanvasController {
    //创建空的数组变量,用来存储 layer
    var layers = [InfiniteScrollView]()

    override func setup() {
        //当 layer 数量小于 10时,执行循环体里的代码
        repeat {
            //创建一个 layer,它的 frame 值和 canvas 的 frame 值一样
            let layer = InfiniteScrollView(frame: view.frame)
            //设置每层 layer 内容的大小,高度为 0 ,防止屏幕垂直滚动
            layer.contentSize = CGSizeMake(layer.frame.size.width * 10, 0)
            //把 layer 添加到 canvas 上以及数组里
            canvas.add(layer)
            layers.append(layer)

            //创建一个中心点变量,用来定位这些 label
            var center = Point(24,canvas.height/2.0)
            //计算 layer 的数量(因为我们要加最后一个 layer,从 10 开始倒序添加)
            let layerNumber = 10 - layers.count
            //创建字体,字号是当前 layer 的数量
            let font = Font(name: "AvenirNext-DemiBold", size:Double(layers.count+1) * 8.0)!
            //创建运行循环体知道每个 layer 都有一个 label
            repeat {
                //创建一个 label
                let label = TextShape(text: "\(layerNumber)", font: font)!
                //居中
                label.center = center
                //更新中心点的位置
                center.x += 130.0
                //把 layer 添加到数组里
                layer.add(label)
            } while center.x < Double(layer.contentSize.width)
        } while layers.count < 10
    }
}

修改原来的设置,加入一个内嵌的 repeat 循环体,直到全部 layer 的包含一个 label —— 每个 label 基于所在的 layer 编号。

现在运行程序,应用里会出现 label 控件,不过!如果我滚动界面,只有一个 layer 在滚动...

下一步就是创建一个观察器,查看一下最上层的 layer,在滚动时将剩下的 layer 移走。在 setup 的最下方,添加下列代码:

if let top = layers.last {
    //创建一个上下文变量
    var c = 0
    //添加 WorkSpace 作为最上层 layer 的 contentOffset 的观察者
    top.addObserver(self, forKeyPath: "contentOffset", options: NSKeyValueObservingOptions.New, context: &c)
}

这一步把 WorkSpace 作为最上层 layer 的 contentOffset 的观察者。现在,让代码更漂亮一些,我创建一个函数,关联 layer 的运动轨迹,改变其他 layer 的轨迹,如下:

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer) {
    //遍历所有的 layer,停在在从上数第二层的 layer 那里
    for i in 0..

漂亮。现在我们知道这是个 layer 绝对会出现了...不过,这里怎么会有一堆的媒体?...测试一下,Jake 看了一下,每层星星的数量大约在 15 个,还给我一个小的白星星。

我接着把内部 repeat 循环里的 label 换成图片,如下:

//实例化中心位置,每个 layer 有 10 * 15 个星星
let starCount = layers.count * 15
canvas.backgroundColor = black
//循环,直到 starCount
for _ in 0..

运行程序,模拟器中应用效果如下:

应用在 iPhone 5 上运行良好,这个是个层次运行料号,那么剩下的问题就是审美的问题,还需要让界面更好看一些。到这时,Jake 基本上制定了背景部分的全部细节。

2.1 单个星座

12个星座的符合由三部分构成:大星星、小星星和线,Jake 用下图记录每种星座中星星的位置:

第 2 章:设计 COSMOS_第4张图片
注意观察大星星和小星星

2.2 三层近景风格 + 运动效果

接下来定义三层近景 layer 里的星星怎么样运动。Jake 的想法是有一个星星移动的地方,所以我们决定使用三层 layer:大星星、小星星、和线。当应用中出现某个特定的符号时,当前的星星需要出现在特定符号的右边,接着所有的东西都在快速移动,从一个星座到另外一个星座的时候,出现非常短的线状动画。

第 2 章:设计 COSMOS_第5张图片

2.3 三层 星星 背景风格 + 运动效果

接下来需要定义背景里有多少星星在动,大约是最上面 layer 的 5%、15%、20%。对每层有多少星星也有一个大概的猜测。

第 2 章:设计 COSMOS_第6张图片

2.4 两层星云层背景风格 + 运动效果

继续,Jake 定义了星云和光晕的外表以及如何移动。这一步甚至比上一步还要简单,因为光晕几乎不懂,星云层大约是 10% 的速度。

第 2 章:设计 COSMOS_第7张图片

2.5 角度/指示器动画

最后一个界面会在屏幕顶部出现一条竖线,with a longer dash every 20 dashes。接着,每个星座到达屏幕的中心位置时,都会出现一个更长的白线,在星座符号的下方:

第 2 章:设计 COSMOS_第8张图片

2.6 最后

最后一件事,写一个清单列出即将要开发的不同的 layer,在他无限的好意下,Jake 发给我下图:

第 2 章:设计 COSMOS_第9张图片

3. 菜单

菜单看起挺简单,实际上不然。唯一需要我搞懂的就是我们给这些星座符合设计什么样的动画效果。

第 2 章:设计 COSMOS_第10张图片
Jake 想用这些符号作为星座的基本外形

实际上,给它们添加动画效果这事简单,难的地方在于创造它们,因为我们希望它们有自己的贝塞尔路径,创建的过程确实痛苦的,因为我们不知道他们的路径点,像是 IllUstrator 这样的软件也不给我们权限获取数据,还有,我不想写一个 SVG 导出器,那也太多余了。

那么,我们该怎么办呢?

使用 PaintCode 画出外形,接着添加曲线轨迹,保存到 Core Graphics 代码里,如下:

UIBezierPath* bezier2Path = UIBezierPath.bezierPath;
[bezier2Path moveToPoint: CGPointMake(250, 200)];
[bezier2Path addLineToPoint: CGPointMake(150, 200)];
[bezier2Path addCurveToPoint: CGPointMake(100, 150) controlPoint1: CGPointMake(122.4, 200) controlPoint2: CGPointMake(100, 177.6)];
...
[bezier2Path closePath];

当我把代码换成下面这样后:

let bezier = Path()

bezier.moveToPoint(Point(250,200))
bezier.addLineToPoint(Point(150,200))
bezier.addCurveToPoint(Point(100,150), control1:Point(122.4,200), control2:Point(100,177.6))
...

事情开始变得更清晰,更容易处理了。现在我还需要得到星座符号的外形添加到 C4 代码里,无需费太多力就能实现我们想要实现的效果。

比如,让 shape 的外形完全和要求的一样:

shape.strokeEnd = 1.0

3.1 红线

走到这一步,我准备创建菜单了,因此需要下面的红线,标注菜单上所有元素的具体的位置、尺寸等等。

Jake 的工作做的真棒,给我准备了这张图:

第 2 章:设计 COSMOS_第11张图片

4. 该进行下一章了

基本的视觉概念都解释了,
现在该做一些实际的开发工作了。不过,在职之前,我总结了一些必须要表明的问题:

  1. 定义外形 - 我会复用很多外形,也会给它们添加动画效果,我会用自定义的贝塞尔曲线路径,而不是单单导入图片资源。
  2. 复杂的动画序列 - 会有非常复杂的动画序列和调速,直到得到正确的菜单外展内收的效果。
  3. 定义手势交互 - 我想让手势交互越简单约好,当然了还要独一无二。
  4. 视差 + 无限滚动视图 - 必须给应用增加视差,我需要非常小心处理,开发完成后,应用的性能表现要非常高才行。

记得删除掉 WorkSpace.swift 文件里的测试代码...只有一个空的 setup() 方法。

继续下一章!

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权。

你可能感兴趣的:(第 2 章:设计 COSMOS)