I have facing issue to make ripples in Square and Stare figure like YRipple
Please help me and suggestion always welcome.
I have facing issue to make ripples in Square and Stare figure like YRipple
Please help me and suggestion always welcome.
One easy way to achieve this is to use UIView
animations. Each ripple is simply an instance of UIView
. The shape can then be simply defined, drawn in one of many ways. I am using the override of draw
rect method:
class RippleEffectView: UIView {
func addRipple(at location: CGPoint) {
let minRadius: CGFloat = 5.0
let maxRadius: CGFloat = 100.0
let startFrame = CGRect(x: location.x - minRadius, y: location.y - minRadius, width: minRadius*2.0, height: minRadius*2.0)
let endFrame = CGRect(x: location.x - maxRadius, y: location.y - maxRadius, width: maxRadius*2.0, height: maxRadius*2.0)
let view = ShapeView(frame: startFrame)
view.shape = .star(cornerCount: 5)
view.backgroundColor = .clear
view.contentMode = .redraw
view.strokeColor = .black
view.strokeWidth = 5.0
addSubview(view)
UIView.animate(withDuration: 1.0, delay: 0.0, options: [.allowUserInteraction]) {
view.frame = endFrame
view.alpha = 0.0
} completion: { _ in
view.removeFromSuperview()
}
}
}
private class ShapeView: UIView {
var fillColor: UIColor?
var strokeColor: UIColor?
var strokeWidth: CGFloat = 0.0
var shape: Shape = .rectangle
override func draw(_ rect: CGRect) {
super.draw(rect)
let path = generatePath()
path.lineWidth = strokeWidth
if let fillColor = fillColor {
fillColor.setFill()
path.fill()
}
if let strokeColor = strokeColor {
strokeColor.setStroke()
path.stroke()
}
}
private func generatePath() -> UIBezierPath {
switch shape {
case .rectangle: return UIBezierPath(rect: bounds.insetBy(dx: strokeWidth*0.5, dy: strokeWidth*0.5))
case .oval: return UIBezierPath(ovalIn: bounds.insetBy(dx: strokeWidth*0.5, dy: strokeWidth*0.5))
case .anglesOnCircle(let cornerCount):
guard cornerCount > 2 else { return .init() }
let center = CGPoint(x: bounds.midX, y: bounds.midY)
let radius = min(bounds.width, bounds.height)*0.5 - strokeWidth*0.5
let path = UIBezierPath()
for index in 0..<cornerCount {
let angle = CGFloat(index)/CGFloat(cornerCount) * (.pi*2.0)
let point = CGPoint(x: center.x + cos(angle)*radius,
y: center.y + sin(angle)*radius)
if index == 0 {
path.move(to: point)
} else {
path.addLine(to: point)
}
}
path.close()
return path
case .star(let cornerCount):
guard cornerCount > 2 else { return .init() }
let center = CGPoint(x: bounds.midX, y: bounds.midY)
let outerRadius = min(bounds.width, bounds.height)*0.5 - strokeWidth*0.5
let innerRadius = outerRadius*0.7
let path = UIBezierPath()
for index in 0..<cornerCount*2 {
let angle = CGFloat(index)/CGFloat(cornerCount) * .pi
let radius = index.isMultiple(of: 2) ? outerRadius : innerRadius
let point = CGPoint(x: center.x + cos(angle)*radius,
y: center.y + sin(angle)*radius)
if index == 0 {
path.move(to: point)
} else {
path.addLine(to: point)
}
}
path.close()
return path
}
}
}
private extension ShapeView {
enum Shape {
case rectangle
case oval
case anglesOnCircle(cornerCount: Int)
case star(cornerCount: Int)
}
}
I used it in a view controller where I replaced main view with this ripple view in Storyboard.
class ViewController: UIViewController {
private var rippleView: RippleEffectView? { view as? RippleEffectView }
override func viewDidLoad() {
super.viewDidLoad()
rippleView?.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onTap)))
}
@objc private func onTap(_ recognizer: UIGestureRecognizer) {
let location = recognizer.location(in: rippleView)
rippleView?.addRipple(at: location)
}
}
I hope the code speaks for itself. It should be no problem to change colors. You could apply some rotation by using transform
on each ripple view...
You could even use images instead of shapes. If image is set to be as templates you could even change colors using tint
property on image view... So limitless possibilities.