我正在尝试制作一个“记录按钮”,这是一个带有手势识别器的UIView,适用于我的应用。现在我正在实现这个功能,当我点击视图时,我想缩小内圈(红圈),但最终会出现意外的转换。我使用UIView.animate函数来执行此操作,以下是我的相关代码:
import UIKit
@IBDesignable
class RecordView: UIView {
@IBInspectable
var borderColor: UIColor = UIColor.clear {
didSet {
self.layer.borderColor = borderColor.cgColor
}
}
@IBInspectable
var borderWidth: CGFloat = 20 {
didSet {
layer.borderWidth = borderWidth
}
}
@IBInspectable
var cornerRadius: CGFloat = 100 {
didSet {
layer.cornerRadius = cornerRadius
}
}
private var fillView = UIView()
private func setupFillView() {
let radius = (self.cornerRadius - self.borderWidth) * 0.95
fillView.frame = CGRect(origin: CGPoint.zero, size: CGSize(width: radius * 2, height: radius * 2))
fillView.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
fillView.layer.cornerRadius = radius
fillView.backgroundColor = UIColor.red
self.addSubview(fillView)
}
override func layoutSubviews() {
super.layoutSubviews()
setupFillView()
}
func didClick() {
UIView.animate(withDuration: 1.0, animations: {
self.fillView.transform = CGAffineTransform(scaleX: 0.6, y: 0.6)
}) { (true) in
print()
}
}
}
在我的ViewController中,我有:
@IBAction func recoreViewTapped(_ sender: UITapGestureRecognizer) {
recordView.didClick()
}
然而它最终会产生这种效果: https://media.giphy.com/media/3ohjUQrWt7vfIxzBrG/giphy.gif。我是初学者,真的不知道我的代码有什么问题?
答案 0 :(得分:2)
问题是您正在应用转换,这会再次触发layoutSubviews
,因此frame
fillView
的重置将应用于转换后的视图
至少有两个选择:
您可以转换整个RecordButton
视图:
@IBDesignable
class RecordView: UIView {
@IBInspectable
var borderColor: UIColor = .clear { didSet { layer.borderColor = borderColor.cgColor } }
@IBInspectable
var borderWidth: CGFloat = 20 { didSet { layer.borderWidth = borderWidth; setNeedsLayout() } }
private var fillView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
private func configure() {
fillView.backgroundColor = .red
self.addSubview(fillView)
}
override func layoutSubviews() {
super.layoutSubviews()
let radius = min(bounds.width, bounds.height) / 2 - borderWidth
fillView.frame = CGRect(origin: CGPoint(x: bounds.midX - radius, y: bounds.midY - radius),
size: CGSize(width: radius * 2, height: radius * 2))
fillView.layer.cornerRadius = radius
}
func didClick() {
UIView.animate(withDuration: 1.0, animations: {
self.transform = CGAffineTransform(scaleX: 0.6, y: 0.6)
}, completion: { _ in
print("completion", #function)
})
}
}
或者您可以将fillView
放入容器中,然后fillView
赢得的转换会触发layoutSubviews
的{{1}} :
RecordView
顺便说一下,还有其他几件小事:
正如您和我在别处讨论过的那样,应该从@IBDesignable
class RecordView: UIView {
@IBInspectable
var borderColor: UIColor = .clear { didSet { layer.borderColor = borderColor.cgColor } }
@IBInspectable
var borderWidth: CGFloat = 20 { didSet { layer.borderWidth = borderWidth; setNeedsLayout() } }
private var fillView = UIView()
private var containerView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
private func configure() {
fillView.backgroundColor = .red
self.addSubview(containerView)
containerView.addSubview(fillView)
}
override func layoutSubviews() {
super.layoutSubviews()
containerView.frame = bounds
let radius = min(bounds.width, bounds.height) / 2 - borderWidth
fillView.frame = CGRect(origin: CGPoint(x: bounds.midX - radius, y: bounds.midY - radius),
size: CGSize(width: radius * 2, height: radius * 2))
fillView.layer.cornerRadius = radius
}
func didClick() {
UIView.animate(withDuration: 1.0, animations: {
self.fillView.transform = CGAffineTransform(scaleX: 0.6, y: 0.6)
}, completion: { _ in
print("completion", #function)
})
}
}
调用初始配置(例如添加子视图)。但是应该从init
调用任何frame
/ bounds
个临时内容。
完全不相关,但传递给layoutSubviews
的{{1}}的参数是一个布尔值,表示动画是否为completion
。如果您不打算使用该布尔值,则应使用UIView.animate(withDuration:animations:completion:)
,而不是finished
。
从长远来看,我建议将"触摸" /手势相关的内容移动到RecordButton中。我很容易想象你会变得更加漂亮:例如一个动画,因为你"触地" (缩小按钮以呈现"压下" vibe)和另一个用于"抬起" (例如,取消按钮并将圆形"记录"按钮转换为方形"停止"按钮)。然后,您可以让按钮在发生重大事件时通知视图控制器(例如记录或停止识别),但会降低视图控制器本身的复杂性。
_
产量: