Swift:UIView.animate意外地工作
我试图做一个“记录按钮”这是一个UIView与我的应用程序的手势识别器。目前我正在实现的功能是,当我点击视图时,我想缩小内圈(红圈),但最终会出现意想不到的变形。我用UIView.animate功能来做到这一点,下面是我的代码相关:Swift: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()
}
然而,这种效果达到: /wp-content/uploads/new2022/20220327voicc/153153152.gif。我是初学者,真的不知道我的代码有什么问题?
回答:
问题是,您正在应用一个转换,它将再次触发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
将不会触发RecordView
的layoutSubviews
:@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
调用或有的东西。完全不相关,但传递给
completion
的参数UIView.animate(withDuration:animations:completion:)
是布尔值,指示动画是否为finished
。如果您不打算使用该布尔值,则应该使用_
,而不是(true)
。长期来看,我建议将“触摸”/手势相关的东西移到RecordButton中。我很容易想象你会变得更加奇特:例如(“缩小”按钮以呈现“压低”的氛围),另一个用于“抬起”(例如,取消按下按钮并将圆形“记录”按钮转换为方块“停止”按钮)。然后,您可以通过该按钮通知视图控制器何时发生重大事件(例如记录或停止识别),但会降低视图控制器本身的复杂性。
protocol RecordViewDelegate: class {
func didTapRecord()
func didTapStop()
}
@IBDesignable
class RecordView: UIView {
@IBInspectable
var borderColor: UIColor = .clear { didSet { layer.borderColor = borderColor.cgColor } }
@IBInspectable
var borderWidth: CGFloat = 20 { didSet { layer.borderWidth = borderWidth; setNeedsLayout() } }
weak var delegate: RecordViewDelegate?
var isRecordButton = true
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)
}
private var radius: CGFloat { return min(bounds.width, bounds.height)/2 - borderWidth }
override func layoutSubviews() {
super.layoutSubviews()
containerView.frame = bounds
fillView.frame = CGRect(origin: CGPoint(x: bounds.midX - radius, y: bounds.midY - radius),
size: CGSize(width: radius * 2, height: radius * 2))
fillView.layer.cornerRadius = isRecordButton ? radius : 0
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
UIView.animate(withDuration: 0.25) {
self.fillView.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
self.fillView.backgroundColor = UIColor(red: 0.75, green: 0, blue: 0, alpha: 1)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first, containerView.bounds.contains(touch.location(in: containerView)) {
if isRecordButton {
delegate?.didTapRecord()
} else {
delegate?.didTapStop()
}
isRecordButton = !isRecordButton
}
UIView.animate(withDuration: 0.25) {
self.fillView.transform = .identity
self.fillView.backgroundColor = UIColor.red
self.fillView.layer.cornerRadius = self.isRecordButton ? self.radius : 0
}
}
}
国债收益率:
以上是 Swift:UIView.animate意外地工作 的全部内容, 来源链接: utcz.com/qa/259740.html