Reputation: 451
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:
Initially the button is clickable and when it is clicked it moves up along with subview.
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)
Upvotes: 2
Views: 1146
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.
When the button is clicked, mainView animates upward and button moves upward as it is subview of mainView.
When button is clicked again, mainView goes to previous position so does the button.
Upvotes: 1