Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS Build an Interactive Story App with Swift 2 Adding Sound Effects Repositioning the Text Field

Brandon Maldonado Alonso
Brandon Maldonado Alonso
10,050 Points

Why my solution of moving my textfield doesn't work?

The problem is that I implemented the first animation to move when the keyboard appear, now i'm trying to do almost the same, just animate the textfield when the keyboard disappear but I don't know why it is not working.

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

// Creation of the textField and the animate-able constraints
let textField = UITextField()
private var textFieldXConstraint: NSLayoutConstraint?
private var textFieldYConstraint: NSLayoutConstraint?

let startButton = UIButton()

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)

    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.keyboardWillDissappear(_:)), name: UIKeyboardWillHideNotification, object: nil)

    textField.delegate = self

    startButton.enabled = false
    startButton.alpha = 0.3
    startButton.setTitle("Start Adventure", forState: UIControlState.Normal)

    startButton.addTarget(self, action: #selector(ViewController.startButtonDidTouch), forControlEvents: UIControlEvents.TouchUpInside)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "startAdventure" {
        if let pageController = segue.destinationViewController as? PageController, let text = textField.text {
            pageController.page = Adventure.story(text)
        }
    }
}

// MARK: Helper methods

func keyboardWillShow(notification: NSNotification) {

    if let userInfo = notification.userInfo, keyboardFrameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue {

        let keyboardFrame = keyboardFrameValue.CGRectValue()

        UIView.animateWithDuration(0.8, animations: {
            self.textFieldYConstraint?.constant -= keyboardFrame.size.height
            self.view.layoutIfNeeded()
        })
    }
}

func keyboardWillDissappear(notification: NSNotification) {

    UIView.animateWithDuration(0.8, animations: {
        self.textFieldYConstraint?.constant += 100
        print(self.textFieldYConstraint!)
        self.view.layoutIfNeeded()
    })

}

// This happen when you press the start adventure button
func startButtonDidTouch() {
    performSegueWithIdentifier("startAdventure", sender: self)
}

// MARK: UI Creation
override func viewWillLayoutSubviews() {
    view.addSubview(startButton)
    startButton.translatesAutoresizingMaskIntoConstraints = false

    startButton.tintColor = UIColor.whiteColor()

    NSLayoutConstraint.activateConstraints([
        startButton.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor),
        startButton.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor, constant: -48.0)
        ])

    view.addSubview(textField)
    textField.translatesAutoresizingMaskIntoConstraints = false

    textField.minimumFontSize = 24.0
    textField.placeholder = "Write your name"
    textField.borderStyle = .RoundedRect

    textFieldXConstraint = NSLayoutConstraint(item: textField, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)

    textFieldYConstraint = NSLayoutConstraint(item: textField, attribute: NSLayoutAttribute.BottomMargin, relatedBy: NSLayoutRelation.LessThanOrEqual, toItem: startButton, attribute: NSLayoutAttribute.TopMargin, multiplier: 1, constant: -24)

    if textFieldXConstraint != nil && textFieldYConstraint != nil {
        view.addConstraint(textFieldXConstraint!)
        view.addConstraint(textFieldYConstraint!)
    }
}

// MARK: TextField Helper Methods

// called when 'return' key pressed. return NO to ignore.
func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}

// called when users tap out of textfield
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    self.view.endEditing(true)
}

// Checks if there is a name to activate the button
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let lenght = (textField.text?.characters.count)! - (range.length) + (string.characters.count)

    if lenght > 0 {
        startButton.enabled = true
        startButton.alpha = 1.0
    } else {
        startButton.enabled = false
        startButton.alpha = 0.3
    }

    return true
}

// MARK: deinit

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)

    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}

}

4 Answers

Andres Aguero
Andres Aguero
30,545 Points

Almost there! Your function for the code constraints is too much. Your function for keyboardWillDissappear should be

func keyboardWillDissappear(notification: NSNotification) {
        UIView.animateWithDuration(0.8) {
            self.textFieldBottomConstraint.constant = 40.0
            self.view.layoutIfNeeded()
        }
}

The code resets the constraints.

Andres Aguero
Andres Aguero
30,545 Points

Interesting seems as if you added the button manually and not from main.storyboard am I correct? The reason why he added the button from the main.storyboard is so that we would be able to manipulate the constraint of the button by assigning it the constraint to an outlet. "@IBOutlet weak var textFieldBottomConstraint: NSLayoutConstraint!"

In your code you did not add an outlet. But your code in theory should work because if you were to "print(self.textFieldYConstraint!)" and compare it from when it was moved the button should have been reset. The button is just not updating its location itself. Not sure if there is some sort of special code for it.

Brandon Maldonado Alonso
Brandon Maldonado Alonso
10,050 Points

I tried to add everything programmatically, I figured out that if I move the code from viewWillLayoutSubview to viewDidLoad the code works how I want, I don't understand why and I'm not sure if this is a good practice, do you have any idea?

Brandon Maldonado Alonso
Brandon Maldonado Alonso
10,050 Points

so where should I implement my auto layout code?

Andres Aguero
Andres Aguero
30,545 Points

If it works in the viewDidLoad then leave it there