     }
 
     fileprivate func animateTap() {
-        guard !alreadyTapped else { return }
-        alreadyTapped = true
-        previousTransform = transform
+        guard !animationState.performed else { return }
+        animationState.performed = true
+        animationState.restoration = transform
         UIView.animate(withDuration: 0.2) {
             let scale: CGFloat = 0.8
-            self.transform = self.previousTransform.concatenating(CGAffineTransform(scaleX: scale, y: scale))
+            self.transform = self.animationState.restoration.concatenating(CGAffineTransform(scaleX: scale, y: scale))
             self.dimmedView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
         }
     }
 
     fileprivate func undoTapAnimation() {
-        guard alreadyTapped else { return }
-        alreadyTapped = false
+        guard animationState.performed else { return }
+        animationState.performed = false
         UIView.animate(withDuration: 0.2) {
-            self.transform = self.previousTransform
+            self.transform = self.animationState.restoration
             self.dimmedView.backgroundColor = nil
         }
-        previousTransform = .identity
+        animationState.restoration = .identity
     }
 }


    fileprivate func clearTouchDownInside() {
        touchingDownInside = false
        forceTouchDownInside = false
    }

    fileprivate func boundsContain(_ touches: Set<UITouch>) -> Bool {


import UIKit

struct AnimationState {
    var performed: Bool = false
    var restoration: CGAffineTransform = .identity
}

class TappableView: UIView {

    fileprivate var touchingDownInside: Bool = false
    fileprivate let dimmedView: UIView
    fileprivate var animationState = AnimationState()
    let contentView: UIView
    var tapped: (() -> Void)?

    convenience init() {
        self.init(frame: .zero)
