在網(wǎng)上看到的UI效果
模仿寫了Swift版本
github地址
效果圖:
-
View的使用:
//創(chuàng)建
let jellyView = HXJellyView()
jellyView.frame = CGRect.init(x: 0, y: 0, width: Main_Width, height: Main_Height)
//添加
view.addSubview(jellyView)
-
實(shí)現(xiàn)方法:
- 控件包括兩個(gè)子控件
一個(gè)是紅色Layer(CAShapeLayer)
一個(gè)是紫色view -
CAShapeLayer使用UIBezierPath描述
紫色View作為UIBezierPath的控制點(diǎn):
- 為控件添加手勢(shì)
紫色點(diǎn)根據(jù)手勢(shì)的移動(dòng)而移動(dòng)
紫色點(diǎn)位置改變,控制點(diǎn)也就被改變了,UIBezierPath就變了,進(jìn)而改變了CAShapeLayer - 松開手后,使用UIView動(dòng)畫做彈性動(dòng)畫
-
代碼:
- 監(jiān)聽屬性,添加手勢(shì)
//創(chuàng)建屬性(控制點(diǎn)的X和Y)
dynamic var curveX : CGFloat = 0.0
dynamic var curveY : CGFloat = 0.0
//使用KVO監(jiān)聽這兩個(gè)屬性
override init(frame: CGRect) {
super.init(frame: frame)
addObserver(self, forKeyPath: "curveX", options: NSKeyValueObservingOptions.new, context: nil)
addObserver(self, forKeyPath: "curveY", options: NSKeyValueObservingOptions.new, context: nil)
//添加手勢(shì)
let pan = UIPanGestureRecognizer.init(target: self, action: #selector(HXJellyView.handlePanAction))
addGestureRecognizer(pan)
}
- 根據(jù)手勢(shì)移動(dòng)讓紫色View執(zhí)行動(dòng)畫,并改變監(jiān)聽屬性
func handlePanAction(){
if isAnimating {
return
}
//手勢(shì)在移動(dòng)的時(shí)候
if pan.state == UIGestureRecognizerState.changed {
//相對(duì)于初始觸點(diǎn)位置
let point = pan.translation(in: self)
//讓紫色點(diǎn)跟著手勢(shì)走
mHeight = point.y + Min_Height
//改變監(jiān)聽屬性的值
curveX = point.x + Main_Width * 0.5
curveY = mHeight > Min_Height ? mHeight : Min_Height
curveView.frame = CGRect(x: curveX, y: curveY, width: 6, height: 6 )
}
//手松開的時(shí)候 做回彈動(dòng)畫
else if pan.state == UIGestureRecognizerState.ended || pan.state == UIGestureRecognizerState.cancelled||pan.state == UIGestureRecognizerState.failed{
isAnimating = true
//松開手了,打開計(jì)時(shí)器,做彈性動(dòng)畫
displayLink.isPaused = false
UIView.animate(withDuration: 1.0,
delay: 0.0,
usingSpringWithDamping: 0.5,
initialSpringVelocity: 0,
options: UIViewAnimationOptions.curveEaseInOut,
animations: {
//讓紫色點(diǎn)產(chǎn)生彈簧效果,路徑跟著黃點(diǎn)走
self.curveView.frame = CGRect(x: Main_Width * 0.5 - 3.0, y: Min_Height, width: 6, height: 6)
}, completion: { (finished) in
print(finished)
if finished{
self.displayLink.isPaused = true
self.isAnimating = false
}
})
}
}
- 手勢(shì)移動(dòng)的時(shí)候,監(jiān)聽屬性被改變了,重新計(jì)算Path
//改變path
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "curveX" || keyPath == "curveY" {
let path = UIBezierPath.init()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: Main_Width, y: 0))
path.addLine(to: CGPoint(x: Main_Width, y: Min_Height))
path.addQuadCurve(to: CGPoint(x: 0, y: Min_Height), controlPoint: CGPoint(x: curveX, y: curveY))
path.close()
shapeLayer.path = path.cgPath
}
}
- 松開手的時(shí)候,計(jì)時(shí)器被打開,紫色額View在做彈性動(dòng)畫,同時(shí)也要更改監(jiān)聽屬性,讓Path也相應(yīng)作出改變
//計(jì)算路徑
func calculatePath(){
//動(dòng)畫開始時(shí) presentation layer開始移動(dòng)绊诲,原始layer隱藏,動(dòng)畫結(jié)束時(shí)褪贵,presentation layer從屏幕上移除驯镊,原始layer顯示
//所以移動(dòng)的是presentation layer
let layer = curveView.layer.presentation()
curveX = (layer?.position.x)!
curveY = (layer?.position.y)!
}
感謝閱讀
你的支持是我寫作的唯一動(dòng)力