Что я делаю: Я создаю музыкальное приложение. В этом музыкальном приложении у меня есть музыкальный проигрыватель, который связан с Apple Music и Spotify. Музыкальный проигрыватель отображает обложку альбома текущей песни на UIImageView
. Всякий раз, когда воспроизводится песня, UIImageView
вращается (как запись на проигрывателе).
В чем моя проблема: Обложка альбома для UIImageView
по умолчанию квадратная,Я округляю углы UIImageView
layer
и задаю UIImageView.clipsToBounds
равным true
, чтобы он выглядел как круг. Всякий раз, когда UIImageView
вращается, некоторые пиксели за пределами UIImageView
layer
(части, которая обрезается после округления изображения) просвечивают.
Вот чтоошибка выглядит так: https://www.youtube.com/watch?v=OJxX5PQc7Jo&feature=youtu.be
Мой код: UIImageView
округляется, устанавливая layer
s cornerRadius
равным UIImageView.frame.height / 2
и устанавливаяUIImageView.clipsToBounds = true
:
class MyViewController: UIViewController {
@IBOutlet var albumArtImageView: UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
albumArtImageView.layer.cornerRadius = albumArtImageView.frame.height / 2
albumArtImageView.clipsToBounds = true
//I've also tried the following code, and am getting the same behavior:
/*
albumArtImageView.layer.cornerRadius = albumArtImageView.frame.height / 2
albumArtImageView.layer.masksToBounds = true
albumArtImageView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner,.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
*/
}
}
Каждый раз, когда нажимается кнопка, UIImageView
начинает вращаться. Я использовал следующее extension
, чтобы сделать вращение UIView
:
extension UIView {
func rotate(duration: Double = 1, startPoint: CGFloat) {
if layer.animation(forKey: UIView.kRotationAnimationKey) == nil {
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotationAnimation.fromValue = startPoint
rotationAnimation.toValue = (CGFloat.pi * 2.0) + startPoint
rotationAnimation.duration = duration
rotationAnimation.repeatCount = Float.infinity
layer.add(rotationAnimation, forKey: UIView.kRotationAnimationKey)
}
}
}
У меня также есть следующее расширение, чтобы завершить вращение:
extension UIView {
...
func stopRotating(beginTime: Double!, startingAngle: CGFloat) -> CGFloat? {
if layer.animation(forKey: UIView.kRotationAnimationKey) != nil {
let animation = layer.animation(forKey: UIView.kRotationAnimationKey)!
let elapsedTime = CACurrentMediaTime() - beginTime
let angle = elapsedTime.truncatingRemainder(dividingBy: animation.duration)/animation.duration
layer.transform = CATransform3DMakeRotation((CGFloat(angle) * (2 * CGFloat.pi)) + startingAngle, 0.0, 0.0, 1.0)
layer.removeAnimation(forKey: UIView.kRotationAnimationKey)
return (CGFloat(angle) * (2 * CGFloat.pi)) + startingAngle
} else {
return nil
}
}
}
Вот какэти функции расширения используются в контексте моего контроллера представления:
class MyViewController: UIViewController {
var songBeginTime: Double!
var currentRecordAngle: CGFloat = 0.0
var isPlaying = false
...
@IBAction func playButtonPressed(_ sender: Any) {
if isPlaying {
if let angle = albumArtImageView.stopRotating(beginTime: songBeginTime, startingAngle: currentRecordAngle) {
currentRecordAngle = angle
}
songBeginTime = nil
} else {
songBeginTime = CACurrentMediaTime()
albumArtImageView.rotate(duration: 3, startPoint: currentRecordAngle)
}
}
}
Итак, все вместе MyViewController
выглядит примерно так:
class MyViewController: UIViewController {
@IBOutlet var albumArtImageView: UIImageView()
var songBeginTime: Double!
var currentRecordAngle: CGFloat = 0.0
var isPlaying = false
override func viewDidLoad() {
super.viewDidLoad()
albumArtImageView.layer.cornerRadius = albumArtImageView.frame.height / 2
albumArtImageView.clipsToBounds = true
}
@IBAction func playButtonPressed(_ sender: Any) {
if isPlaying {
if let angle = albumArtImageView.stopRotating(beginTime: songBeginTime, startingAngle: currentRecordAngle) {
currentRecordAngle = angle
}
songBeginTime = nil
} else {
songBeginTime = CACurrentMediaTime()
albumArtImageView.rotate(duration: 3, startPoint: currentRecordAngle)
}
}
}