PullDown.gif
人要是不興奮,抗利尿激素都不給力。Talk is cheap,show code,留著給自己以后看。
首先自定義一個view,在創建的時候添加了一個紅色視圖,放在了上方跟隨手拖拽的初始位置,只是通過這個紅色的視圖更直觀的看到拖拽情況。image.png
然后創建一個CAShapeLayer,設置渲染填充顏色,路徑等拖拽的時候時時更新重繪
private lazy var shapeLayer: CAShapeLayer = {
let shapeLayer = CAShapeLayer()
shapeLayer.fillColor = UIColor.cyan.cgColor
return shapeLayer
}()
給當前自定義的view添加拖拽手勢,根據拖拽的位置繪制shapeLayer。
let tap = UIPanGestureRecognizer.init(target: self, action: #selector(handleTapGestureRecognizer(tap:)))
addGestureRecognizer(tap)
添加一個計時器,在拖拽結束的時候繼續重回shapeLayer,計時器默認暫停狀態,在手勢結束的時候開啟
displayLink = CADisplayLink.init(target: self, selector: #selector(caculatePath))
displayLink.add(to: RunLoop.current, forMode: .defaultRunLoopMode)
displayLink.isPaused = true
描繪路徑,根據路徑繪制shapeLayer,路徑從左上角即zero點開始,直線繪制到右上角,接著直線繪制到右下角,然后根據控制點繪制曲線到左下角,下圖中黑色是繪制方向,紅點是繪制的主要點,綠色是繪制曲線的控制點
image.png
func updateShapePath(){
let path = UIBezierPath()
path.move(to: CGPoint.zero)
path.addLine(to: CGPoint.init(x: Device_Width, y: 0))
path.addLine(to: CGPoint.init(x: Device_Width, y: Default_Height))
path.addQuadCurve(to: CGPoint.init(x: 0, y: Default_Height), controlPoint: CGPoint.init(x: controlPoint_X, y: controlPoint_Y))
shapeLayer.path = path.cgPath
}
接著在拖拽界面的時候根據手勢進行計算路徑,如果處于剛剛松手的狀態,即處于果凍效果的動畫中,就不用在這里做任何處理,此時會計時器會去計算松手時手勢獲取最后的觸摸點進行繪制。如若處于非動畫中,判斷手勢是否處于移動中,就時刻獲取是手勢的當前觸摸點進行修改控制點的坐標修改控制點的值,繪制shapeLayer。如果處于拖拽取消,拖拽結束,拖拽失敗的情況,就開啟計時器,控制點的位置重新計算路徑繪制shapeLayer。繪制結束后暫停計時器,修改動畫狀態
// 根據手勢計算路徑繪制shapeLayer
func handleTapGestureRecognizer(tap: UIPanGestureRecognizer){
if !isAnimateing {
if tap.state == .changed {
let point = tap.translation(in: tap.view)
controlPoint_X = Device_Width / 2 + point.x
controlPoint_Y = point.y + Default_Height
if controlPoint_Y < Default_Height {
controlPoint_Y = Default_Height
}
var frame = visionView.frame
frame.origin.x = controlPoint_X
frame.origin.y = controlPoint_Y
visionView.frame = frame
updateShapePath()
} else if tap.state == .cancelled || tap.state == .ended || tap.state == .failed {
self.displayLink.isPaused = false
self.isAnimateing = true
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
self.visionView.frame = CGRect.init(x: Device_Width / 2 - 1.5, y: Default_Height, width: 3, height: 3)
}, completion: { (finished) in
if finished {
self.displayLink.isPaused = true
self.isAnimateing = false
}
})
}
}
}
// 計時器計算動畫狀態中的控制點
func caculatePath(){
let layer = visionView.layer.presentation()
self.controlPoint_X = layer?.position.x ?? Device_Width / 2
self.controlPoint_Y = layer?.position.y ?? Default_Height
self.updateShapePath()
}
此時自定義view已經結束,調試的時候也很方便。創建自定義view添加到視圖界面展示就好,不要忘記view默認是不可交互的,打開交互才可以。
let jellyView = JellyView.init(frame: self.view.bounds)
jellyView.backgroundColor = .purple
jellyView.isUserInteractionEnabled = true
view.addSubview(jellyView)