I'm trying to make a "record button" which is a UIView with a gesture recognizer for my app. Right now I'm implementing the feature that when I click the view, I want to scale down the inner circle (the red one) however it ends up with an unexpected transformation. I use UIView.animate function to do this, and below is my relating code:
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()
}
}
}
In my ViewController, I have:
@IBAction func recoreViewTapped(_ sender: UITapGestureRecognizer) {
recordView.didClick()
}
However it ends up with this effect: https://media.giphy.com/media/3ohjUQrWt7vfIxzBrG/giphy.gif. I'm a beginner and really don't know what's wrong with my code?
The issue is that you're applying a transform, which is triggering the
layoutSubviews
again, so the resetting of theframe
offillView
is being applied on the transformed view.There are at least two options:
You could just transform the whole
RecordButton
view:Or you could put the
fillView
inside a container, and then the transform of thefillView
won't trigger thelayoutSubviews
of theRecordView
:By the way, a few other little things:
As you and I discussed elsewhere, the initial configuration (e.g. adding of the subview) should be called from
init
. But anyframe
/bounds
contingent stuff should be called fromlayoutSubviews
.Completely unrelated, but the parameter passed to
completion
ofUIView.animate(withDuration:animations:completion:)
is a Boolean indicating whether the animation isfinished
or not. If you're not going to use that Boolean, you should use_
, not(true)
.Longer term, I'd suggest moving the "touches"/gesture related stuff into the RecordButton. I can easily imagine you getting fancier: e.g. one animation as you "touch down" (shrink the button to render the "depress" vibe) and another for "lift up" (e.g. unshrink the button and convert the round "record" button to a square "stop" button). You can then have the button inform the view controller when something significant happens (e.g. record or stop recognized), but reduces complexity from the view controller itself.
That yields: