第五个案例,Banner 滚动
这个案例的难点在于一个事件触发 2 个操作,需要通过一个变量把两个控件关联起来。
思路整理:
- 导入静态样式
- 创建 pageComponent
- 创建底部 indicators
- 创建关联事件
导入静态样式
在 Sketch 上把不需要运动的静态控件画好,导入 Framer. 如顶部状态栏和底部 Tab 栏。
# Sketch Import
sketch = Framer.Importer.load "imported/page-indicators"
注意:
- 在构建动画的时候需要提前思考,哪些元素是静态的,哪些元素是动态的。前期规划好,为后期节省大量的时间。
创建 pageComponent
创建所需的 Framer 翻页控件。
# Create pageComponent
page = new PageComponent
y: 128
scrollVertical: false
width: Screen.width
height: 970
# 保证合适的间距
contentInset: {top: 32, right: 32}
# 翻页动画效果
animationOptions:
curve: Spring(damping: .8)
# Define variables
indicators = []
pageNumber = 3
# Generate each page
for i in [0...pageNumber]
card = new Layer
parent: page.content
backgroundColor: "#fff"
borderRadius: 8
width: page.width - 64
height: 950
x: page.width * i + 32
shadowY: 1
shadowBlur: 6
shadowColor: "rgba(0,0,0,0.2)"
注意:
- 这里有一个 Bug,
right: 32
,我个人不知道其逻辑原因。我只有加了这个,最后一个页面才能居中。逻辑上说,我的代码是不需要这个值的。不清楚是不是 Framer 的一个 Bug, 有待考证。
创建底部 indicators
对应三个页面,创建三个指示符,同时给其添加default
和active
两种状态,方便后续对其操作。
indicator = new Layer
backgroundColor: "#222"
width: 12
height: 12
# 居中指示符
x: Screen.width / 2 - (pageNumber * 12 * 2) / 2 + 12 * i * 2
y: 1167
borderRadius: "50%"
# 添加动态状态
indicator.states =
default:
opacity: .2
scale: 1
active:
opacity: .9
scale: 1.2
animationOptions:
time: .5
# 加入数组
indicators.push(indicator)
注意:
-
Screen.width / 2 - (pageNumber * 12 * 2) / 2 + 12 * i * 2
, 可以通过屏幕的中点减去元素一半的长度
这个公式居中元素位置。
创建关联事件
通过 page.horizontalPageIndex()
获得关联值,通过这个数值搭建起页面和其对应指示符之间的关系。
# 交互部分
# 设置初始页
cur = page.horizontalPageIndex(page.currentPage)
indicator.stateSwitch('default') for indicator in indicators
indicators[cur].animate('active')
# 翻页, 隐藏面板缩放
page.on Events.Move, ->
x = page.scrollX
for subLayer in page.content.subLayers
offset = Math.abs(x - subLayer.x)
subLayer.scale = Utils.modulate(offset, [0, 750], [1, .8])
# 翻页, 更新指示符状态
page.on "change:currentPage", ->
indicator.stateSwitch('default') for indicator in indicators
cur = page.horizontalPageIndex(page.currentPage)
indicators[cur].animate('active')
注意:
-
offset = Math.abs(x - subLayer.x)
用于判断当前页面偏离原位置的多少,从而决定其动态大小。 -
indicator.stateSwitch('default') for indicator in indicators
相当于
for indicator in indicators
indicator.stateSwitch('default')
跟大神学的,这么写可以节省一行空间。
小结
在践行中发现了一个道理,不要等到自己准备好了一门知识,再去用它。而是在掌握了足够实践的知识之后,就立刻去实践。把知识用于实践是检验已有知识和学习未知知识的更高效方法。
虽然自己本科时学习过面向对象编程,但是一直掌握的不好。不能自己用 Javascript 实现,给自己定一个小目标,近期用面向对象的思想写一个 Javascript 的小程序作为 Framer 10 天课程的完结篇。加油。
Reference
Framer 线上演示:https://framer.cloud/sxvXo/
完整代码
# Author: Joey
# Date: 07 May 2017
# Sketch Import
sketch = Framer.Importer.load "imported/page-indicators"
# Create pageComponent
page = new PageComponent
y: 128
scrollVertical: false
width: Screen.width
height: 970
# 保证合适的间距
contentInset: {top: 32, right: 32}
# 翻页动画效果
animationOptions:
curve: Spring(damping: .8)
# Define variables
indicators = []
pageNumber = 3
# Generate each page
for i in [0...pageNumber]
card = new Layer
parent: page.content
backgroundColor: "#fff"
borderRadius: 8
width: page.width - 64
height: 950
x: page.width * i + 32
shadowY: 1
shadowBlur: 6
shadowColor: "rgba(0,0,0,0.2)"
indicator = new Layer
backgroundColor: "#222"
width: 12
height: 12
# 居中指示符
x: Screen.width / 2 - (pageNumber * 12 * 2) / 2 + 12 * i * 2
y: 1167
borderRadius: "50%"
# 添加动态状态
indicator.states =
default:
opacity: .2
scale: 1
active:
opacity: .9
scale: 1.2
animationOptions:
time: .5
# 加入数组
indicators.push(indicator)
# 交互部分
# 设置初始页
cur = page.horizontalPageIndex(page.currentPage)
indicator.stateSwitch('default') for indicator in indicators
indicators[cur].animate('active')
# 翻页, 隐藏面板缩放
page.on Events.Move, ->
x = page.scrollX
for subLayer in page.content.subLayers
offset = Math.abs(x - subLayer.x)
subLayer.scale = Utils.modulate(offset, [0, 750], [1, .8])
# 翻页, 更新指示符状态
page.on "change:currentPage", ->
indicator.stateSwitch('default') for indicator in indicators
cur = page.horizontalPageIndex(page.currentPage)
indicators[cur].animate('active')