我有一个“U”形,我UIBezierPath
用它来制作动画。我也有一个滚动视图。我的目标是制作一个自定义的“拉动刷新”动画。path
myImage.layer
我遇到的问题是我希望我myImage.layer
根据滚动视图滚动的程度进行更新。
随着滚动视图被拉下,myImage.layer
动画沿着“U”形移动path
。这是path
我创建为UIBezierPath
.
这就是我计算scrollView被拉下多远的方法:
func scrollViewDidScroll(scrollView: UIScrollView) {
let offsetY = CGFloat(max(-(scrollView.contentOffset.y + scrollView.contentInset.top), 0.0))
self.progress = min(max(offsetY / frame.size.height, 0.0), 1.0)
if !isRefreshing {
redrawFromProgress(self.progress)
}
}
这是动态更新位置的功能(它不起作用):
func redrawFromProgress(progress: CGFloat) {
// PROBLEM: This is not correct. Only the `x` position is dynamic based on scrollView position.
// The `y` position is static.
// I want this to be dynamic based on how much the scrollView scrolled.
myImage.layer.position = CGPoint(x: progress, y: 50)
}
基本上,这就是我想要的:
如果滚动的scrollView是0.0,那么
myImage.layer
位置应该是CGPoint(x: 0, y: 0)或者path
.如果滚动的scrollView 是0.5(50%),那么
myImage.layer
位置应该是50%path
,我不知道CGPoint 值会是什么。等等...
我尝试UIBezierPath
根据滚动视图的百分比获取 CGPoint 值,将 CGPoint 值分配给它,但不知道如何执行此操作。我也看过这篇文章,但我无法让它为我工作。
编辑问题1:
通过使用这个扩展,我能够得到一个数组,CGPoints
其中包含基于我的 10 个值UIBezierPath
:
extension CGPath {
func forEachPoint(@noescape body: @convention(block) (CGPathElement) -> Void) {
typealias Body = @convention(block) (CGPathElement) -> Void
func callback(info: UnsafeMutablePointer<Void>, element: UnsafePointer<CGPathElement>) {
let body = unsafeBitCast(info, Body.self)
body(element.memory)
}
// print(sizeofValue(body))
let unsafeBody = unsafeBitCast(body, UnsafeMutablePointer<Void>.self)
CGPathApply(self, unsafeBody, callback)
}
func getPathElementsPoints() -> [CGPoint] {
var arrayPoints : [CGPoint]! = [CGPoint]()
self.forEachPoint { element in
switch (element.type) {
case CGPathElementType.MoveToPoint:
arrayPoints.append(element.points[0])
case .AddLineToPoint:
arrayPoints.append(element.points[0])
case .AddQuadCurveToPoint:
arrayPoints.append(element.points[0])
arrayPoints.append(element.points[1])
case .AddCurveToPoint:
arrayPoints.append(element.points[0])
arrayPoints.append(element.points[1])
arrayPoints.append(element.points[2])
default: break
}
}
return arrayPoints
}
我还重写了上面调用的函数redrawFromProgress(progress: CGFloat)
:
func redrawFromProgress(progress: CGFloat) {
let enterPath = paths[0]
let pathPointsArray = enterPath.CGPath
let junctionPoints = pathPointsArray.getPathElementsPoints()
// print(junctionPoints.count) // There are 10 junctionPoints
// progress means how much the scrollView has been pulled down,
// it goes from 0.0 to 1.0.
if progress <= 0.1 {
myImage.layer.position = junctionPoints[0]
} else if progress > 0.1 && progress <= 0.2 {
myImage.layer.position = junctionPoints[1]
} else if progress > 0.2 && progress <= 0.3 {
myImage.layer.position = junctionPoints[2]
} else if progress > 0.3 && progress <= 0.4 {
myImage.layer.position = junctionPoints[3]
} else if progress > 0.4 && progress <= 0.5 {
myImage.layer.position = junctionPoints[4]
} else if progress > 0.5 && progress <= 0.6 {
myImage.layer.position = junctionPoints[5]
} else if progress > 0.6 && progress <= 0.7 {
myImage.layer.position = junctionPoints[6]
} else if progress > 0.7 && progress <= 0.8 {
myImage.layer.position = junctionPoints[7]
} else if progress > 0.8 && progress <= 0.9 {
myImage.layer.position = junctionPoints[8]
} else if progress > 0.9 && progress <= 1.0 {
myImage.layer.position = junctionPoints[9]
}
}
如果我很慢地拉下滚动视图,myImage.layer
实际上会遵循路径。唯一的问题是,如果我非常快速地下拉滚动视图,那么会myImage.layer
跳转到最后一点。可能是因为我写if statement
上面的方式吗?
有任何想法吗?