3

I have set my UIkeyboarddismissmode to be .Interactive, and I do not know how to resize the UITextView so that the keyboard would not cover the content. I also have a UIToolbar as the inputaccessory.

Here is my code.

@IBOutlet weak var textView: UITextView!

override func viewDidLoad() {
    super.viewDidLoad()

    self.addDoneButtonOnKeyboard()

    self.textView.keyboardDismissMode = .Interactive
}

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(true)

    // Add notification about keyboard
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardNotification:"), name:UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardNotification:"), name:UIKeyboardWillHideNotification, object: nil)
    //        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardFrameDidChange:"), name:UIKeyboardWillChangeFrameNotification, object: nil)
}

override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(true)
    NSNotificationCenter.defaultCenter().removeObserver(UIKeyboardWillShowNotification)
    NSNotificationCenter.defaultCenter().removeObserver(UIKeyboardWillHideNotification)
}


// The UIToolbar

var toolbar = UIToolbar()

func addDoneButtonOnKeyboard()
{
    var doneToolbar: UIToolbar = UIToolbar(frame: CGRectMake(0, 0, 320, 44))
    doneToolbar.barStyle = UIBarStyle.Default

    var flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
    var photo: UIBarButtonItem = UIBarButtonItem(title: "Add Photo", style: UIBarButtonItemStyle.Bordered, target: self, action: Selector("photoButtonAction"))
    var done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Done, target: self, action: Selector("doneButtonAction"))

    var items = NSMutableArray()
    items.addObject(photo)
    items.addObject(flexSpace)
    items.addObject(done)

    doneToolbar.items = items
    doneToolbar.sizeToFit()

    doneToolbar.tintColor = UIColor(red: 240/225, green: 42/225, blue: 20/225, alpha: 1)
    doneToolbar.translucent = true

    self.toolbar = doneToolbar
    self.textView.inputAccessoryView = self.toolbar
}

func keyboardFrameDidChange(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        var endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
        var beginFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()

        let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseInOut.rawValue
        let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)

        var animationDuration = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0

        var newFrame = self.textView.frame
        var keyboardFrameEnd = self.view.convertRect(endFrame!, toView: nil)
        var keyboardFrameBegin = self.view.convertRect(beginFrame!, toView: nil)

        newFrame.origin.y -= (keyboardFrameBegin.origin.y - keyboardFrameEnd.origin.y)
        self.textView.frame = newFrame

        UIView.animateWithDuration(animationDuration,
            delay: NSTimeInterval(0),
            options: animationCurve,
            animations: { self.view.layoutIfNeeded() },
            completion: nil)
    }

}

The above code only makes the textView move in a weird way and I don't know how to achieve the effect like the Message app.

Update:

func keyboardFrameEnd(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        var endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()

        // Change contentInset
        self.textView.contentInset.bottom = endFrame!.height
        self.textView.scrollIndicatorInsets.bottom = endFrame!.height
    }
}

I changed my code to above. But sometimes when I release the keyboard halfway, the scrollView would suddenly bounce to the bottom which is very weird. Any suggestion?

Daniyar
  • 2,975
  • 2
  • 26
  • 39
Henry Ngan
  • 572
  • 1
  • 4
  • 24
  • try this: [link](http://stackoverflow.com/questions/11282449/move-uiview-up-when-the-keyboard-appears-in-ios). I know it is Objective-C code but you can adapt it to Swift. – dehlen Dec 24 '14 at 10:29
  • http://stackoverflow.com/questions/25693130/move-textfield-when-keyboard-appears-swift look at this – Sport Dec 24 '14 at 10:35
  • I have tried the methods above but they're all hardcoded with animation. My keyboarddissmissmode is set to be Interactive, which means you drag the keyboard down manually, not animated, like the iMessage app. – Henry Ngan Dec 24 '14 at 10:41

2 Answers2

4

UITextView is a scroll view. You do not need to resize it when the keyboard appears: you should adjust it's contentInset property, increasing the .bottom by the height of the keyboard.

Gregzo
  • 1,194
  • 7
  • 18
  • Thanks. It partly achieved the desired effect. However, the scrollbar on the right does not change, which is confusing. Any method to solve that? – Henry Ngan Dec 24 '14 at 10:58
  • Solved the problem with scrollIndicatorInsets.bottom. Thanks! – Henry Ngan Dec 24 '14 at 11:01
  • That's the idea: the scroll view extends behind the keyboard, an inset is simply added at the bottom so that you can scroll further down and see the bottom of the text. – Gregzo Dec 24 '14 at 11:05
  • 1
    But then I found another bug. When the content is so short, like, only 2 lines in the textView, you cannot dismiss the keyboard interactively. Also, when the content is so short that you can view all content within the screen without scrolling, when you dismiss the keyboard, the textView would suddenly bounce upwards then back to original after the keyboard is dismissed. This looks so weird. – Henry Ngan Dec 24 '14 at 11:59
0

It can apply whether you have tabbar or not. And it would perfectly restore view that moved by keyboard to original position.

// Set this up in storyboard first. 
// It's a vertical spacing constraint between your text view and bottom of superview.
@IBOutlet weak var bottomSpacingConstraint: NSLayoutConstraint! 

override func viewDidLoad() {
        super.viewDidLoad()            

        //    Receive(Get) Notification
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardNotification:", name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardNotification:", name: UIKeyboardWillHideNotification, object: nil)


        self.originalConstraint = self.keyboardHeightLayoutConstraint?.constant //for original coordinate.
}

func keyboardNotification(notification: NSNotification) {
        let isShowing = notification.name == UIKeyboardWillShowNotification

        var tabbarHeight: CGFloat = 0
        if self.tabBarController? != nil {
            tabbarHeight = self.tabBarController!.tabBar.frame.height
        }
        if let userInfo = notification.userInfo {
            let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
            let duration:NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
            let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
            let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseInOut.rawValue
            let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
            self.keyboardHeightLayoutConstraint?.constant = isShowing ? (endFrame!.size.height - tabbarHeight) : self.originalConstraint!
            UIView.animateWithDuration(duration,
                delay: NSTimeInterval(0),
                options: animationCurve,
                animations: { self.view.layoutIfNeeded() },
                completion: nil)
        }
}

Move textfield when keyboard appears swift

Community
  • 1
  • 1
Jeff Gu Kang
  • 4,749
  • 2
  • 36
  • 44