How to make a UIScrollView auto scroll when a UITextField becomes a first responder

前端 未结 11 1799
有刺的猬
有刺的猬 2021-01-31 03:24

I\'ve seen posts around here that suggest that UIScrollViews should automatically scroll if a subview UITextField becomes the first responder; however,

11条回答
  •  礼貌的吻别
    2021-01-31 03:43

    Other solutions I saw, let you set the offset to the origin of the textField but this makes the scroller view go beyond it bounds. I did this adjustment to the offset instead to not go beyond the bottom nor the top offsets.

    Set the keyboardHeightConstraint to the bottom of the page. When the keyboard shows, update its constraint's constant to negative the keyboard height. Then scroll to the responderField as we will show below.

    @IBOutlet var keyboardHeightConstraint: NSLayoutConstraint?
    var responderField: String?
    
    @objc func keyboardNotification(notification: NSNotification) {
         guard let keyboardValue = notification.userInfo [UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
         let keyboardHeight = keyboardValue.cgRectValue.height
    
         keyboardHeightConstraint?.constant = -keyboardHeight
         scroll(field: responderField!)
    }
    
    func textFieldDidBeginEditing(_ textField: UITextField) {
         responderField = textField
    }
    

    Now we want to make sure we do not scroll greater than the bottom offset nor less than the top offset. At the same time, we want to calculate the offset of the field's maxY value. To do that, we subtract the scrollView.bounds.size.height from the maxY value.

    let targetOffset = field.frame.maxY - scrollView.bounds.size.height

    I found it nicer to scroll an extra distance of the keyboard height, but you could neglect that if you want to scroll right below the field.

    let targetOffset = keyboardHeight + field.frame.maxY - scrollView.bounds.size.height

    Remember to add the scrollView.contentInset.bottom if you have the tab bar visible.

    func scroll(field: UITextField) {
            guard let keyboardConstraintsConstant = keyboardHeightConstraint?.constant else { return }
            let keyboardHeight = -keyboardConstraintsConstant
            
            view.layoutIfNeeded()
            let bottomOffset = scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom
            let topOffset = -scrollView.safeAreaInsets.top
            let targetOffset = keyboardHeight + field.frame.maxY + scrollView.contentInset.bottom - scrollView.bounds.size.height
            let adjustedOffset = targetOffset > bottomOffset ? bottomOffset : (targetOffset < topOffset ? topOffset : targetOffset)
            scrollView.setContentOffset(CGPoint(x: 0, y: adjustedOffset), animated: true)
    }
    

提交回复
热议问题