04 April 2016



가끔씩 매터리얼 디자인의 물결 효과를 보면서 iOS에 적용해볼까 했지만, 이 효과때문에 Material 라이브러리를 추가해야하나 했습니다. 그래서 CALayer를 이용해서 구현해보았습니다.

class ViewController: UIViewController {

override func viewDidLoad() {
	super.viewDidLoad()
	let tap = UITapGestureRecognizer(target: self, action: #selector(self.tap(_:)))
	self.view.addGestureRecognizer(tap)
	self.view.layer.masksToBounds = true
	self.view.backgroundColor = UIColor.orangeColor()
}

func tap(recognizer: UITapGestureRecognizer) {
	let hitPoint = recognizer.locationInView(self.view)
	let rippleEffectLayer = CALayer()
	rippleEffectLayer.frame = CGRectMake(hitPoint.x - 5, hitPoint.y - 5, 5, 5)
	rippleEffectLayer.cornerRadius = rippleEffectLayer.frame.height / 2
	rippleEffectLayer.masksToBounds = true;
	rippleEffectLayer.backgroundColor = UIColor(white: 1.0, alpha: 0.2).CGColor
	rippleEffectLayer.zPosition = 1.0
	self.view.layer.addSublayer(rippleEffectLayer)
}

rippleEffectLayer는 super.layer를 덮을 정도로 커야됩니다. super.layer의 높이와 너비 중 가장 큰 값을 찾고, CATransform3DMakeScale를 사용하기 위해 비율을 구합니다.

func tap(recognizer: UITapGestureRecognizer) {
	...
	let maxSize = max(rippleEffectLayer.superlayer!.frame.width, rippleEffectLayer.superlayer!.frame.width)
	let minSize = min(rippleEffectLayer.frame.width, rippleEffectLayer.frame.height)
	let scaleRate = (maxSize / minSize) * 2 * 1.42
}

CATransform3DMakeScale을 사용하여 rippleEffectLayer를 늘리고, rippleEffectLayer의 backgroundColor를 clearColor로 바꾸도록 애니메이션를 만듭니다.

func tap(recognizer: UITapGestureRecognizer) {
	...
	...
	CATransaction.begin()
	CATransaction.setCompletionBlock {
		rippleEffectLayer.removeFromSuperlayer()
	}
	let group = CAAnimationGroup()
	group.duration = 0.5
	group.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)

	let scaleAnimation = CABasicAnimation(keyPath: "transform")
	scaleAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
	scaleAnimation.fromValue = NSValue(CATransform3D: CATransform3DMakeScale(1, 1, 1))
	scaleAnimation.toValue = NSValue(CATransform3D: CATransform3DMakeScale(scaleRate, scaleRate, 1))

	let colorAnimation = CABasicAnimation(keyPath: "backgroundColor")
	colorAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
	colorAnimation.toValue = UIColor.clearColor().CGColor

	group.animations = [scaleAnimation, colorAnimation]

	rippleEffectLayer.addAnimation(group, forKey: "all")

	CATransaction.commit()
}

다음은 위의 코드를 적용한 화면입니다.


이러한 효과나 화면을 구성하는데는 Xcode Playground를 이용하여 화면을 바로 확인할 수 있으며, 화면 효과등을 실시간으로 보도록 XCPlaygroundPage.currentPage.liveView에 view를 할당하면 다음 영상처럼 확인할 수 있습니다.