gpt4 book ai didi

ios - Swift:UIView.animate 工作意外

转载 作者:搜寻专家 更新时间:2023-11-01 07:06:41 27 4
gpt4 key购买 nike

我正在尝试为我的应用制作一个“记录按钮”,它是一个带有手势识别器的 UIView。现在我正在实现这样一个功能,即当我单击 View 时,我想缩小内圈(红色圆圈),但它最终会发生意想不到的转变。我使用 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 .我是初学者,真的不知道我的代码有什么问题?

最佳答案

问题是你正在应用一个转换,它再次触发 layoutSubviews,所以 fillViewframe 的重置正在应用于转换后的 View 。

至少有两种选择:

  1. 您可以只转换整个 RecordButton View :

    @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)
    })
    }

    }
  2. 或者您可以将 fillView 放入容器中,然后 fillView 的转换不会触发 layoutSubviews 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)
    })
    }

    }

顺便说一下其他一些小事:

  • 正如您和我在别处讨论的那样,初始配置(例如添加 subview )应该从 init 调用。但是任何 frame/bounds 偶然的东西都应该从 layoutSubviews 中调用。

  • 完全不相关,但是传递给UIView.animate(withDuration:animations:completion:)completion的参数是一个 bool 值,表示动画是否为finished 与否。如果您不打算使用该 bool 值,则应使用 _,而不是 (true)

  • 从长远来看,我建议将“触摸”/手势相关内容移至 RecordButton。我可以很容易地想象你变得更加狂热:例如一个动画是你“按下”(缩小按钮以呈现“按下”的感觉),另一个是“抬起”(例如,取消缩小按钮并将圆形“记录”按钮转换为方形“停止”按钮)。然后,您可以让按钮在发生重大事件时通知 View Controller (例如记录或停止识别),但会降低 View Controller 本身的复杂性。

    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
    }

    }
    }

    产生:

    enter image description here

关于ios - Swift:UIView.animate 工作意外,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47615855/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com