dev
dev

Reputation: 451

UIButton is not clickable after first click

I am trying to bring a subview from bottom when button is clicked. But only for the first time the button is clickable. For second click after animation button is not clickable.

Here is the code.

class AnimateView: UIView {
var button: UIButton!
var menuView: UIView!
var mainView: UIView!

   override init(frame: CGRect) {
        super.init(frame: frame)
        mainView = UIView(frame: CGRect(x: 0, y: 0, width: 
        self.frame.size.width, height: self.frame.size.height))

        mainView.clipsToBounds = true
        mainView.backgroundColor = .clear
        mainView.isUserInteractionEnabled = true
        mainView.isExclusiveTouch = true
        self.addSubview(mainView)

        let theRect = CGRect(x: self.frame.size.width / 2 - 44 / 2, y: 0, 
        width: 44, height: 44)
        button = UIButton(frame: theRect)
        check.layer.cornerRadius = btnView.frame.size.height / 2
        mainView.addSubview(self.check)
        mainView.bringSubview(toFront: check)
        check.addTarget(self, action: #selector(buttonClick(_:)), 
        for:.touchUpInside)

        let newRect = CGRect(x: 0, y: check.frame.height, width: 
        self.frame.size.width, height: self.mainView.frame.size.height)
        menuView = UIView(frame: newRect)
        menuView.backgroundColor = .blue
        mainView.addSubview(menuView)

}

 required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func buttonClick(_ sender: UIButton) {
        toggleMenu()
    }


    func toggleMenu() {
        if check.transform == CGAffineTransform.identity {
            UIView.animate(withDuration: 1, animations: {
                self.check.transform = CGAffineTransform(scaleX: 12, y: 12)
                self.mainView.transform = CGAffineTransform(translationX: 0, y: -120)
                self.check.transform = CGAffineTransform(rotationAngle: self.radians(180)) // 180 is 3.14 radian
                self.setNeedsLayout()
            }) { (true) in
                UIView.animate(withDuration: 0.5, animations: {

                })
            }
        } else {
            UIView.animate(withDuration: 1, animations: {
                // .identity sets to original position
                //self.btnView.transform = .identity
                self.mainView.transform = .identity
                self.button.transform = .identity
            })
        }

    }
}

This class is called from another UIView class like this

class MainViewClass: UIView {
     var animateView: AnimateView!

     override init(frame: CGRect) {
            animateView = AnimateView(frame: CGRect(x: 0, y: self.frame.size.height - 44 - 44 - 20, width: self.frame.size.width, height: 122+44))
            //animateView.clipsToBounds = true
            self.addSubview(animateView)
            self.bringSubview(toFront: animateView)
    }

     required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    } 
}

When the screen first appears:

enter image description here

Initially the button is clickable and when it is clicked it moves up along with subview. enter image description here

Now the button is not clickable. When I saw the frame of button it is same as when screen initially appears with button touching the screen bottom even though it moves up. What I am intending is to show the screen with animation from bottom when button is clicked and move to default position for second time click.

But if I place the button as subview inside self, not as subview for mainView, then the button is clickable but it remains in the same position even after view is animated and moved up.

self.addSubview(button)

enter image description here

Upvotes: 2

Views: 1146

Answers (1)

dev
dev

Reputation: 451

So, I finally got the solution of what I was intending to achieve before and after animation.

The reason for the UIButton not receiving any touch event after the animation is that after animation, the UIButton moves upward as it is subview of mainView. Due to this, it is out of bound of its superView and does not respond to any click event. Although I moved button along with its superView which is mainView, but button did not respond to touch event. Then, I tested the whether the button bound is within mainView using hitTest:

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let pointForTargetView: CGPoint = button.convert(point, from: mainView)
        if button.bounds.contains(pointForTargetView) {
            print("Button pressed")
            return button.hitTest(pointForTargetView, with:event)
        }
        return super.hitTest(point, with: event)   
    }

This if condition:

button.bounds.contains(pointForTargetView)

Returns false when button is pressed after animation.

So, I need to capture touch event on subview which is out the its superview frame.

Using hitTest() solves my problem. Here's the link which helped me. Capturing touches on a subview outside the frame of its superview using hitTest:withEvent:

Swift 3

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

    if clipsToBounds || isHidden || alpha == 0 {
        return nil
    }

    for subview in subviews.reversed() {
        let subPoint = subview.convert(point, from: self)
        if let result = subview.hitTest(subPoint, with: event) {
            return result
        }
    }

    return nil
}

The screen shots: When screen first appears, button is at bottom of screen, subview is hidden below the button.

enter image description here

When the button is clicked, mainView animates upward and button moves upward as it is subview of mainView.

enter image description here

When button is clicked again, mainView goes to previous position so does the button.

enter image description here

Upvotes: 1

Related Questions