Kouder Kouder - 15 days ago 11
Swift Question

UIView disappears after user interaction

whenever I click a textfield inside the view, then click the other text field, the view disappears. Strange... Can anyone help?

It's the view in the middle.

I animate the view using facebook pop. Here is my animation engine code:
import UIKit
import pop

class AnimationEngine {

class var offScreenRightPosition: CGPoint {
return CGPoint(x: UIScreen.main.bounds.width + 250,y: UIScreen.main.bounds.midY - 75)
}

class var offScreenLeftPosition: CGPoint{
return CGPoint(x: -UIScreen.main.bounds.width,y: UIScreen.main.bounds.midY - 75)
}

class var offScreenTopPosition: CGPoint{
return CGPoint(x: UIScreen.main.bounds.midX,y: -UIScreen.main.bounds.midY)
}

class var screenCenterPosition: CGPoint {
return CGPoint(x: UIScreen.main.bounds.midX, y: UIScreen.main.bounds.midY - 75)
}

let ANIM_DELAY : Int = 1
var originalConstants = [CGFloat]()
var constraints: [NSLayoutConstraint]!

init(constraints: [NSLayoutConstraint]) {

for con in constraints {
originalConstants.append(con.constant)
con.constant = AnimationEngine.offScreenRightPosition.x
}

self.constraints = constraints
}

func animateOnScreen(_ delay: Int) {

let time = DispatchTime.now() + Double(Int64(Double(delay) * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)

DispatchQueue.main.asyncAfter(deadline: time) {

var index = 0
repeat {
let moveAnim = POPSpringAnimation(propertyNamed: kPOPLayoutConstraintConstant)
moveAnim?.toValue = self.originalConstants[index]
moveAnim?.springBounciness = 8
moveAnim?.springSpeed = 8

if (index < 0) {
moveAnim?.dynamicsFriction += 10 + CGFloat(index)
}

let con = self.constraints[index]
con.pop_add(moveAnim, forKey: "moveOnScreen")

index += 1

} while (index < self.constraints.count)
}

}

class func animateToPosisition(_ view: UIView, position: CGPoint, completion: ((POPAnimation?, Bool) -> Void)!) {
let moveAnim = POPSpringAnimation(propertyNamed: kPOPLayerPosition)
moveAnim?.toValue = NSValue(cgPoint: position)
moveAnim?.springBounciness = 8
moveAnim?.springSpeed = 8
moveAnim?.completionBlock = completion
view.pop_add(moveAnim, forKey: "moveToPosition")
}
}


Then here is my viewcontroller code where the view is inside in:

import UIKit
import pop


class LoginVC: UIViewController, UITextFieldDelegate {

override var prefersStatusBarHidden: Bool {
return true
}

@IBOutlet weak var emailLoginVCViewConstraint: NSLayoutConstraint!
@IBOutlet weak var emailLoginVCView: MaterialView!
@IBOutlet weak var emailAddressTextField: TextFieldExtension!
@IBOutlet weak var passwordTextField: TextFieldExtension!

var animEngine : AnimationEngine!

override func viewDidAppear(_ animated: Bool) {
self.emailLoginVCView.isUserInteractionEnabled = true
}

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.view.bringSubview(toFront: emailAddressTextField)
self.animEngine = AnimationEngine(constraints: [emailLoginVCViewConstraint])
self.emailAddressTextField.delegate = self
self.passwordTextField.delegate = self
emailAddressTextField.allowsEditingTextAttributes = false
}


func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if (textField === emailAddressTextField) {
passwordTextField.becomeFirstResponder()
} else if (textField === passwordTextField) {
passwordTextField.resignFirstResponder()
} else {
// etc
}

return true
}

@IBAction func emailTapped(_ sender: AnyObject) {
AnimationEngine.animateToPosisition(emailLoginVCView, position: AnimationEngine.screenCenterPosition, completion: { (POPAnimation, Bool)
in
})
}

@IBAction func exitTapped(_ sender: AnyObject) {
AnimationEngine.animateToPosisition(emailLoginVCView, position: AnimationEngine.offScreenRightPosition, completion: { (POPAnimation, Bool)
in
})
}

}


Last here is my hierchy and options: (my view's name is emailLoginVCView). Also when I was debugging when I clicked another textfield I set a breakpoint so I got this info: enter image description here

enter image description here
enter image description here

Answer
  1. I have a constraint that binds the center of the login view with the center of the main screen

  2. when I create the AnimationEngine,I pass it that constraint, and it sets its constant to be the offScreenRightPosition.x

  3. when I bring up the email login sheet, I'm not changing the constant of the constraint; I'm just changing the position of the view

  4. which means that autolayout thinks it’s supposed to still be offscreen

  5. when the second textfield becomes active, that’s somehow triggering auto-layout to re-evaluate the constraints, and it sees that the login view’s position doesn’t match what the constraint says it should be so....

  6. Autolayout moves it offscreen

So if I add this in emailTapped(_:), the problem goes away :)

@IBAction func emailTapped(_ sender: AnyObject) { AnimationEngine.animateToPosisition(emailLoginVCView, position: AnimationEngine.screenCenterPosition, completion: { (POPAnimation, Bool) in self.emailLoginVCViewConstraint.constant = 0 }) }