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,因此framefillView正在应用于转换后的视图。

至少有两个选项:

  1. 你可以只改变整个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)

    })

    }

    }

  2. 或者你可以把fillView一个容器内,并随后变换fillView将不会触发RecordViewlayoutSubviews

    @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

回到顶部