UIButton Animations not working on UIScrollView - swift

I have button animations that are not working on my ScrollView. I have other VCs that are just UIViews and animations work just fine.
So I tried unchecking from the Attributes Inspector and adding...
self.scrollView.delaysContentTouches = false
...in my viewDidLoad, but it had effect.
I also found that tapping does not trigger the animation but holding on the button for a second or more does and haptic presses also trigger the animation.
This is my animation code:
extension UIButton {
func startAnimatingPressActions() {
addTarget(self, action: #selector(animateDown), for: [.touchDown, .touchDragEnter])
addTarget(self, action: #selector(animateUp), for: [.touchDragExit, .touchCancel, .touchUpInside, .touchUpOutside])
}
#objc private func animateDown(sender: UIButton) {
animate(sender, transform: CGAffineTransform.identity.scaledBy(x: 0.95, y: 0.95))
}
#objc private func animateUp(sender: UIButton) {
animate(sender, transform: .identity)
}
private func animate(_ button: UIButton, transform: CGAffineTransform) {
UIView.animate(withDuration: 0.4,
delay: 0,
usingSpringWithDamping: 0.5,
initialSpringVelocity: 3,
options: [.curveEaseInOut],
animations: {
button.transform = transform
}, completion: nil)
}
}
I am able to get this animation working, but it doesn't feel quite right. So I'd rather not use the code below. But it does work. So I'm not sure what in the code above is causing the problem.
extension UIButton {
func pulsate() {
let pulse = CASpringAnimation(keyPath: "transform.scale")
pulse.duration = 0.2
pulse.fromValue = 0.96
pulse.toValue = 1.0
pulse.repeatCount = 0
pulse.initialVelocity = 0.5
pulse.damping = 1.0
layer.add(pulse, forKey: nil)
}
}

I had the same issue and I solved unchecking the delay touch down button in the scrollview's attributes inspector :
ScrollView's attrobutes inspector

Related

UIButton resize animation is not animating

I'm trying to make that my button double its size using the UIView animation, but for some reason it is not working it the size goes right, but no animated.
The function that should animate the button resizing
Irrelevant code above
#objc func createButtonPressed(){
//Removes the bottom stack with buttons
if let stackButton = self.view.viewWithTag(50){
stackButton.removeFromSuperview()
}
//Add the button back with half ares size
bottomHolder.addSubview(rightButton)
rightButton.setImage(nil, for: .normal)
rightButton.addTarget(self, action: #selector(anima), for: .touchUpInside)
rightButton.topAnchor.constraint(equalTo: bottomHolder.topAnchor).isActive = true
rightButton.trailingAnchor.constraint(equalTo: bottomHolder.trailingAnchor).isActive = true
rightButton.bottomAnchor.constraint(equalTo: bottomHolder.bottomAnchor).isActive = true
}
#objc func anima(){
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.rightButton.leadingAnchor.constraint(equalTo: self.bottomHolder.leadingAnchor).isActive = true
self.rightButton.layoutIfNeeded()
}, completion: nil)
}
Irrelevant code below
try this one:
let buttonFinalWidth = UIScreen.main.bounds.width
DispatchQueue.main.async {
UIView.animate(withDuration: 5.0) {
self.rightButton.widthAnchor.constraint(equalToConstant: buttonFinalWidth).isActive = true
self.view.layoutIfNeeded()
}
}

UIView alpha does not update after first call to change it. (Swift 4.2)

I have a UIView on which I want to change the alpha from 0 to 0.5 when the user opens a slide out menu. When the user taps the darkened area the alpha should go back to 0. Currently, when the menu button is tapped the alpha changes to 0.5 adding a dimming effect to the view. However, a breakpoint and print statement show that when tapping the UIView the line to change the alpha back to 0 runs, but the UI still shows a 0.5 alpha. Everywhere I have looked the code is exactly the same, so I am unsure what I am doing wrong.
let dimView = UIView()
func setupMenuButton() {
let menuButton = UIBarButtonItem(title: "Menu", style: .plain, target: self, action: #selector(showMenu))
navigationItem.rightBarButtonItem = menuButton
}
#objc func showMenu() {
//TODO: present menu and dim background
if let window = UIApplication.shared.keyWindow {
let dimView = UIView()
dimView.backgroundColor = UIColor.black
dimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dismissDimView)))
window.addSubview(dimView)
dimView.frame = window.frame
dimView.alpha = 0
UIView.animate(withDuration: 0.5, animations: {
dimView.alpha = 0.5
})
}
}
#objc func dismissDimView() {
UIView.animate(withDuration: 0.5, animations: {
self.dimView.alpha = 0
print("dim view is not transparent")
})
}
The dimView created in showMenu is not the same dimView created in the first line. You are creating a brand new dimView in showMenu.
One way to fix this is to not create a new dimView in showMenu, and use the one declared outside instead:
#objc func showMenu() {
//TODO: present menu and dim background
if let window = UIApplication.shared.keyWindow {
// notice I deleted a line here
dimView.backgroundColor = UIColor.black
dimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dismissDimView)))
window.addSubview(dimView)
dimView.frame = window.frame
dimView.alpha = 0
UIView.animate(withDuration: 0.5, animations: {
dimView.alpha = 0.5
})
}
}
#objc func dismissDimView() {
UIView.animate(withDuration: 0.5, animations: {
self.dimView.alpha = 0
// here I remove the dimView from the window so that it can be added back in the next time showMenu is called
}, completion: { [weak self] _ in self?.dimView.removeFromSuperView() })
}

Strange animation 'lag' after launch screen disappears and before viewDidAppear() method runs

After launch screen dismisses itself logo and title of my app (they are in container) should go closer to the top of the screen. Between dismissing launch screen and viewDidAppear method there is a strange 'blink' of my container in the background. As you can see I am using snapkit but it should have nothing to do with the problem. Here is my code:
class WelcomeScreenViewController: UIViewController {
var welcomeScreenView: WelcomeScreenView {
return view as! WelcomeScreenView
}
override func loadView() {
let contentView = WelcomeScreenView(frame: .zero)
view = contentView
}
override func viewDidLoad() {
super.viewDidLoad()
self.welcomeScreenView.checkWeatherButton.transform = CGAffineTransform(translationX: 0, y: 200)
self.welcomeScreenView.checkWeatherButton.addTarget(self, action: #selector(showCityChoiceVC), for: .touchUpInside)
navigationController?.isNavigationBarHidden = true
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.welcomeScreenView.appNameLogoContainerVerticalConstraint?.isActive = false
self.welcomeScreenView.appNameLogoContainer.snp.makeConstraints({ (make) in
make.top.equalTo(self.welcomeScreenView).offset(100)
})
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, options: [], animations: {
self.welcomeScreenView.layoutIfNeeded()
self.welcomeScreenView.checkWeatherButton.transform = CGAffineTransform(translationX: 0, y: 0)
}, completion: nil)
}
#objc private func showCityChoiceVC() {
self.navigationController?.pushViewController(RegisterViewController(), animated: true)
}
Blinking comes from setting constraints in viewDidAppear. Use viewWillAppear or viewDidLoad instead. viewDidAppear is invoked when your view actually appears on screen. So any changes that happen will be visible to the user.

Swift animation - Touchdown doesn't work well

I'm trying to create de same effect than the app "Music" :
When I click on a button, there is a view behind and when the button is not focused anymore, the view is hidden. I do this with TouchUpInside and TouchDown funcs.
#IBAction func pressed(_ sender: UIButton) {
UIView.animate(withDuration: 0.25, animations: {
self.backgroundMoreView.alpha = 0.0
self.backgroundMoreView.transform = CGAffineTransform(scaleX:
1.2, y: 1.2)
sender.transform = CGAffineTransform.identity
}) { (_) in
self.backgroundMoreView.transform = CGAffineTransform.identity
}
}
#IBAction func unpressed(_ sender: UIButton) {
UIView.animate(withDuration: 0.25) {
self.backgroundMoreView.alpha = 0.3
sender.transform = CGAffineTransform(scaleX: 0.8, y:
0.8)
}
}
The problem is that, when I click and hold focus, and then I swipe out of the button, the function unpressed() is not called and the button stay "focused".
I don't know how to fix it.
This should solve the problem:
button.addTarget(self, action: #selector(unpressed(sender:)), for: .touchUpOutside)
Or connect it using storyboard to the same action (unpressed) with touchUpOutside

Switching between UITextViews resets view Layout

I implemented some functions to move the UIView, whenever a TextField or a TextView is tapped. The height for the UIView to move upwards is calculated depending how much the keyboard would overlap the active TextField or TextView. When I tap outside of the TextField, or -View the keyboard will be dismissed and the View will be resetted. Now everything is working fine, but when I switch from one TextField directly to another above (without dismissing the keyboard) it seems like the UIView will return to the initial position, instead of just keeping the shifted view (because the now active TextView would not be overlapped by the keyboard since it is above the former). It looks like some method is called to reset the view, resulting in the keyboard overlapping the upper TextView. Is there a way to suppress this behavior?
private func observeKeyboardNotification(){
NotificationCenter.default.addObserver(self, selector: #selector(keyboardShow), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardHide), name: .UIKeyboardWillHide, object: nil)
}
var distanceOfKeyboardToTextView: CGFloat = 0
var activeTextElement: UIView?
var viewIsShifted = false
func keyboardShow(notification: NSNotification){
findActiveTextField(subviews: self.view.subviews, textField : &activeTextElement)
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue, let activeTextElement = activeTextElement, !viewIsShifted {
let viewYPosition = (activeTextElement.superview?.convert(activeTextElement.frame.origin, to: nil).y)! + activeTextElement.frame.height
let keyboardYPosition = view.frame.height - keyboardSize.height
distanceOfKeyboardToTextView = viewYPosition - keyboardYPosition
if distanceOfKeyboardToTextView > 0 {
UIView.animate(withDuration: 0.5,
delay: 0,
usingSpringWithDamping: 1,
initialSpringVelocity: 1, options: .curveEaseOut,
animations: {
self.customView.frame = CGRect(x: 0, y: self.customView.frame.origin.y - self.distanceOfKeyboardToTextView, width: self.customView.frame.width, height: self.customView.frame.height)
}, completion: nil)
viewIsShifted = true
}
}
activeTextElement = nil
}
func keyboardHide(){
UIView.animate(withDuration: 0.5,
delay: 0,
usingSpringWithDamping: 1,
initialSpringVelocity: 1, options: .curveEaseOut,
animations: {
self.customView.frame = CGRect(x: 0, y: self.customView.frame.origin.y + self.distanceOfKeyboardToTextView, width: self.customView.frame.width, height: self.customView.frame.height)
}, completion: nil)
viewIsShifted = false
distanceOfKeyboardToTextView = 0
}
func findActiveTextField (subviews : [UIView], textField : inout UIView?) {
guard textField == nil else { return }
for view in subviews {
if view.isFirstResponder {
textField = view
break
}
else if !view.subviews.isEmpty {
findActiveTextField (subviews: view.subviews, textField: &textField)
}
}
}
Update:
After tapping from an active textfield directly onto another textfield, keyboardShow is call, but since the view is already shifed, UIView.animate will not be performed. However, the view is resetted like no keyboard would be displayed, but since the other textfield is active, the keyboard is visible.
I dismiss the keyboard using this extension:
extension UIViewController {
//functions to hide the keyboard
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
view.addGestureRecognizer(tap)
}
func dismissKeyboard() {
view.endEditing(true)
}
}
and in my ViewController:
override func viewDidLoad() {
super.viewDidLoad()
observeKeyboardNotification()
self.hideKeyboardWhenTappedAround()
...
}