0

I have UIScrollView which has a UIView (basically a content view) in it. In contentView, I have UITextFields and a UIButton. At first, elements are inside UIScrollView directly. When keyboard opens, If UITextField is below keyboard, scrollview scrolls to show the content. After, I put them inside a ContentView, It started nothing to work. What am I doing wrong?

I searched below posts but not sure why my code isn't working.

How do I scroll the UIScrollView when the keyboard appears?

P.S: I know there are lots of examples in the community but I'm not sure which will be best approach. When this one was working, It was a simple and light answer but not sure why not It isn't working.

@objc override func keyboardWillShow(notification: NSNotification){
//Need to calculate keyboard exact size due to Apple suggestions
if let frameValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
    keyboardHeight = frameValue.cgRectValue.size.height

        let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardHeight, right: 0.0)
        self.scrollView.contentInset = contentInsets
        self.scrollView.scrollIndicatorInsets = contentInsets
}
}

How I Give Constraints:

contentView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(contentView)
contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
scrollView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(scrollView)

contentView.addSubview(TextField1)
contentView.addSubview(TextField2)
contentView.addSubview(button)
scrollView.anchor(header.bottomAnchor, left: self.view.leftAnchor, bottom: self.view.bottomAnchor, right: self.view.rightAnchor, topConstant: 20, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
TextField1.anchor(contentView.topAnchor, left: self.contentView.leftAnchor, bottom: nil, right: self.contentView.rightAnchor, topConstant: 5, leftConstant: 25, bottomConstant: 0, rightConstant: 25, widthConstant: 0, heightConstant: 70)
TextField1.widthAnchor.constraint(equalTo: self.view.widthAnchor, constant: -50).isActive = true

TextField2.anchor(TextField1.bottomAnchor, left: self.contentView.leftAnchor, bottom: nil, right: self.contentView.rightAnchor, topConstant: 5, leftConstant: 25, bottomConstant: 0, rightConstant: 25, widthConstant: 0, heightConstant: 70)
Button.anchor(TextField2.bottomAnchor, left: self.contentView.leftAnchor, bottom: self.contentView.bottomAnchor, right: self.contentView.rightAnchor, topConstant: 30, leftConstant: 25, bottomConstant: 20, rightConstant: 25, widthConstant: 0, heightConstant: 40)

EDIT: Another approach I tried (which Apple recommended). This aRect.Contains always returns true.

    if let frameValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
    keyboardHeight = frameValue.cgRectValue.size.height

    var contentInsets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardHeight, right: 0.0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets

    // If active text field is hidden by keyboard, scroll it so it's visible
    // Your application might not need or want this behavior.
    //CGRect(x: 0, y: self.header.frame.maxY, width: self.view.frame.width, height: self.view.frame.height - self.header.frame.maxY)
    var aRect: CGRect = self.view.frame
    aRect.size.height -= keyboardHeight
    aRect.size.height -= header.frame.maxY
    if !aRect.contains(activeTextField.frame.origin) {
        var scrollPoint = CGPoint(x: 0.0, y: activeTextField.frame.origin.y - (keyboardHeight))
        scrollView.setContentOffset(scrollPoint, animated: true)
    }
    }
Emre Önder
  • 1,845
  • 1
  • 13
  • 49

2 Answers2

0

After an hour work, I find the solution. I'm sharing the answer instead of deleting the post cuz my problem was because UIScrollView doesn't content whole screen. There is an header and a label above UIScrollView . All of the answers in the community, target If UIScroll content whole screen.

       @objc override func keyboardWillShow(notification: NSNotification){
    //Need to calculate keyboard exact size due to Apple suggestions
    if let frameValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
        keyboardHeight = frameValue.cgRectValue.size.height
        let scrollViewRect: CGRect = view.convert(scrollView.frame, from: scrollView.superview)
        let hiddenScrollViewRect: CGRect = scrollViewRect.intersection(frameValue.cgRectValue)

        // Figure out where the two frames overlap, and set the content offset of the scrollview appropriately
        let contentInsets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: hiddenScrollViewRect.size.height, right: 0.0)
        scrollView.contentInset = contentInsets
        scrollView.scrollIndicatorInsets = contentInsets

        var visibleRect: CGRect = activeTextField.frame
        visibleRect = scrollView.convert(visibleRect, from: activeTextField.superview)
        visibleRect = visibleRect.insetBy(dx: 0.0, dy: -5.0)
        scrollView.scrollRectToVisible(visibleRect, animated: true)
    }
Emre Önder
  • 1,845
  • 1
  • 13
  • 49
0

The simple way to achieve this is by using IQKeyboardManager library.

Checkout the link: https://github.com/hackiftekhar/IQKeyboardManager

SAIF
  • 116
  • 8