Swift 圆形图片动画
Swift Circular image Animation
我有一个显示图像的 UIImageView
,图像不是完全正方形,因为它构成 iPhone 相机,我希望它显示为圆形,当用户触摸图像时,启动圆变大的动画并将图像设置为全屏,例如在顶部有一个圆形蒙版,然后 de mask 变大让全屏看到原始图像,我不知道如何制作它。
您可以通过使用计时器调整图像视图上的蒙版来实现。您应该使用一种特殊类型的计时器,即 "display link",它是唯一定时的最佳屏幕更新。
例如:
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
weak var mask: CAShapeLayer?
override func viewDidLoad() {
super.viewDidLoad()
// add mask to imageview and save reference to it
let mask = CAShapeLayer()
mask.fillColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1).cgColor
mask.strokeColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0).cgColor
imageView.layer.mask = mask
self.mask = mask
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// update the mask for the image view for the size of the view (which was unknown at `viewDidLoad`, but is known here)
if mask != nil {
updatePath(percent: 0)
}
}
@IBAction func didTapButton(_ sender: Any) {
// when we tap button, start display link which will drive the animation
start = CACurrentMediaTime()
let displayLink = CADisplayLink(target: self, selector: #selector(handleDisplaylink(_:)))
displayLink.add(to: .main, forMode: .commonModes)
}
var start: CFTimeInterval! // when the animation was started
let duration: CFTimeInterval = 0.5 // how long will the animation take
@objc func handleDisplaylink(_ displayLink: CADisplayLink) {
// calculate, based upon elapsed time, how far along we are
let percent = CGFloat(min(1, (CACurrentMediaTime() - start) / duration))
// update the path based upon what percent of the animation has been completed
updatePath(percent: percent)
// if we're done, stop display link and go ahead and remove mask now that it's not needed any more
if percent >= 1 {
displayLink.invalidate()
imageView.layer.mask = nil
}
}
/// Update the circular mask for the image view based upon what percent of the animation is done
private func updatePath(percent: CGFloat) {
let center = CGPoint(x: imageView.bounds.midX, y: imageView.bounds.midY)
let startRadius = min(imageView.bounds.width, imageView.bounds.height) * 0.4 // start radius is 40% of smallest dimension
let endRadius = hypot(imageView.bounds.width, imageView.bounds.height) * 0.5 // stop radius is the distance from the center to the corner of the image view
let radius = startRadius + (endRadius - startRadius) * percent // given percent done, what is the radius
mask?.path = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: .pi * 2, clockwise: true).cgPath
}
}
即达到:
我有一个显示图像的 UIImageView
,图像不是完全正方形,因为它构成 iPhone 相机,我希望它显示为圆形,当用户触摸图像时,启动圆变大的动画并将图像设置为全屏,例如在顶部有一个圆形蒙版,然后 de mask 变大让全屏看到原始图像,我不知道如何制作它。
您可以通过使用计时器调整图像视图上的蒙版来实现。您应该使用一种特殊类型的计时器,即 "display link",它是唯一定时的最佳屏幕更新。
例如:
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
weak var mask: CAShapeLayer?
override func viewDidLoad() {
super.viewDidLoad()
// add mask to imageview and save reference to it
let mask = CAShapeLayer()
mask.fillColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1).cgColor
mask.strokeColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0).cgColor
imageView.layer.mask = mask
self.mask = mask
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// update the mask for the image view for the size of the view (which was unknown at `viewDidLoad`, but is known here)
if mask != nil {
updatePath(percent: 0)
}
}
@IBAction func didTapButton(_ sender: Any) {
// when we tap button, start display link which will drive the animation
start = CACurrentMediaTime()
let displayLink = CADisplayLink(target: self, selector: #selector(handleDisplaylink(_:)))
displayLink.add(to: .main, forMode: .commonModes)
}
var start: CFTimeInterval! // when the animation was started
let duration: CFTimeInterval = 0.5 // how long will the animation take
@objc func handleDisplaylink(_ displayLink: CADisplayLink) {
// calculate, based upon elapsed time, how far along we are
let percent = CGFloat(min(1, (CACurrentMediaTime() - start) / duration))
// update the path based upon what percent of the animation has been completed
updatePath(percent: percent)
// if we're done, stop display link and go ahead and remove mask now that it's not needed any more
if percent >= 1 {
displayLink.invalidate()
imageView.layer.mask = nil
}
}
/// Update the circular mask for the image view based upon what percent of the animation is done
private func updatePath(percent: CGFloat) {
let center = CGPoint(x: imageView.bounds.midX, y: imageView.bounds.midY)
let startRadius = min(imageView.bounds.width, imageView.bounds.height) * 0.4 // start radius is 40% of smallest dimension
let endRadius = hypot(imageView.bounds.width, imageView.bounds.height) * 0.5 // stop radius is the distance from the center to the corner of the image view
let radius = startRadius + (endRadius - startRadius) * percent // given percent done, what is the radius
mask?.path = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: .pi * 2, clockwise: true).cgPath
}
}
即达到: