728x90
Ripple Effect
- 아래의 이미지와 같이 버튼이나 뷰를 클릭했을 때 마치 물결이 퍼지듯 원형 모향의 애니메이션이 퍼져나가면서 사용자에게 클릭을 인지시키는 효과
- 위의 구글 material에서 pod으로 다운받아 사용해도 된다.
Code
- UIView을 상속받은 protocol을 만들어서, 최대한 재사용이 가능하게끔 만듬
- 원리는 아래와 같다.
- UIView의 touchesBegan에서 rippleLayer의 setRippleAt 메서드를 호출한다.
- 터치한 지점의 CGPoint를 기준으로 원형의 CAShapeLayer를 만들어서 추가한다.
- 추가한 circleLayer에 alpha애니메이션, scale 애니메이션을 넣는다.
- 예제: https://github.com/Sky-Titan/RippleEffectExample
import UIKit
// MARK: RippledProtocol
protocol RippledProtocol: UIView {
/// ripple 효과 색상
var rippleColor: UIColor? { get set }
/// ripple 효과의 alpha값
var rippleAlpha: CGFloat { get set }
var rippleLayer: RippleLayer { get }
func touchesBeganForRipple(_ touches: Set<UITouch>, with event: UIEvent?)
}
extension RippledProtocol {
var rippleLayer: RippleLayer {
layer as! RippleLayer
}
var rippleColor: UIColor? {
get {
rippleLayer.rippleColor
}
set {
rippleLayer.rippleColor = newValue
setNeedsDisplay()
}
}
var rippleAlpha: CGFloat {
get {
rippleLayer.rippleAlpha
}
set {
rippleLayer.rippleAlpha = newValue
setNeedsDisplay()
}
}
func touchesBeganForRipple(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let point = touch.location(in: self)
rippleLayer.setRippleAt(point)
}
}
}
// MARK: RippleLayer
class RippleLayer: CALayer {
var rippleColor: UIColor? = .white
var rippleAlpha: CGFloat = 0.3
private var circleLayer: CAShapeLayer?
fileprivate func setRippleAt(_ point: CGPoint) {
self.circleLayer?.removeFromSuperlayer()
let radius = radiusForRippleCircle(point)
//ripple 효과를 보여줄 원형 layer
let circle = CAShapeLayer()
circle.anchorPoint = CGPoint(x: 0.5, y: 0.5)
circle.position = CGPoint(x: point.x, y: point.y)
circle.path = UIBezierPath(arcCenter: CGPoint(x: circle.frame.width / 2, y: circle.frame.height / 2), radius: radius, startAngle: 0, endAngle: .pi * 2, clockwise: true).cgPath
circle.fillColor = rippleColor?.cgColor
circle.opacity = 0
self.masksToBounds = true
self.addSublayer(circle)
self.circleLayer = circle
circle.add(rippleAnimation(), forKey: "ripple")
}
//터치한 위치를 기준으로 View의 상하좌우 간격 중 가장 긴 간격이 radius
private func radiusForRippleCircle(_ point: CGPoint) -> CGFloat {
let distanceX: CGFloat = max(self.frame.width - point.x, point.x)
let distanceY: CGFloat = max(self.frame.height - point.y, point.y)
return max(distanceX, distanceY)
}
//완성된 ripple Animation
private func rippleAnimation() -> CAAnimationGroup {
let animationGroup: CAAnimationGroup = CAAnimationGroup()
animationGroup.duration = 0.45
animationGroup.fillMode = .forwards
let showingDuration: CGFloat = 0.3
animationGroup.animations = [sizingAnimation(duration: showingDuration),
showingAlphaAnimation(duration: showingDuration),
hidingAlphaAnimation(beginTime: showingDuration, duration: 0.15)
]
animationGroup.beginTime = CACurrentMediaTime()
return animationGroup
}
//circle 등장 시 사이즈 확장 애니메이션
private func sizingAnimation(duration: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: "transform.scale")
animation.fromValue = 0
animation.toValue = 1
animation.duration = duration
animation.beginTime = 0
animation.fillMode = .forwards
return animation
}
//circle 등장 시 alpha 애니메이션
private func showingAlphaAnimation(duration: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: "opacity")
animation.fromValue = 0
animation.toValue = rippleAlpha
animation.duration = duration
animation.beginTime = 0
animation.fillMode = .forwards
return animation
}
//circle 사라질 시 alpha 애니메이션
private func hidingAlphaAnimation(beginTime: CGFloat, duration: CGFloat) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: "opacity")
animation.fromValue = rippleAlpha
animation.toValue = 0
animation.duration = duration
animation.beginTime = beginTime
animation.fillMode = .forwards
return animation
}
}
// MARK: RippledButton
class RippledButton: UIButton, RippledProtocol {
override class var layerClass: AnyClass {
RippleLayer.self
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.touchesBeganForRipple(touches, with: event)
}
}
728x90
'iOS > 예제' 카테고리의 다른 글
[iOS 예제] Recording Wave View 만들기 (0) | 2022.07.02 |
---|---|
[iOS 예제] Roulette 만들기 (0) | 2022.06.25 |
[iOS 예제] CircleProgressView 만들기 (0) | 2021.12.11 |
[iOS 예제] UIView에 원형으로 shadow 넣기 (0) | 2021.12.07 |
[iOS 예제] Drag and Drop가능한 UIView만들기 (0) | 2021.12.05 |
댓글