Swift를 사용하여 키보드로 뷰 이동


278

뷰의 아래쪽 절반에 텍스트 필드가있는 앱이 있습니다. 이것은 텍스트 필드에 입력 할 때 키보드가 텍스트 필드를 덮음을 의미합니다.

입력하는 동안보기를 위로 이동하여 입력하는 내용을 확인한 다음 키보드가 사라지면 원래 위치로 다시 이동하는 방법은 무엇입니까?

나는 모든 곳을 보았지만 모든 솔루션은 Obj-C에있는 것으로 보이며 아직 변환 할 수는 없습니다.

도움을 주시면 감사하겠습니다.


이를 수행하는 가장 좋은 방법은 컨텐츠를 UIScrollView 안에 배치 한 다음, 스크롤보기의 contentInset 특성을 표시 될 때 키보드 높이 로 조정하는 것입니다. 키보드 높이를 가정하지 마십시오. "키보드에 표시"알림의 값을 사용하십시오.
— nielsbot 2016 년

1
사실, 애플 문서는 "키보드 관리"에 따라,이 작업을 수행하는 방법을 알려 : developer.apple.com/library/ios/documentation/StringsTextFonts/...
— nielsbot

11
아래의 모든 답변은 한 가지 경우를 고려하지 않는다고 생각합니다. 여러 개의 텍스트 필드가 있고 일부가 화면 상단에있는 경우 어떻게해야합니까? 언제든지 사용자는 내가 정답 여부를 감지합니다 확신,이 화면을 넘어 상승, 그 텍스트 필드를 탭it is actually needed to scroll view up when keyboard appears
— theDC

이 답변은 현재 편집중인 텍스트 필드가 키보드와 동일한 공간을 차지하는지 확인하여 키보드가 나타날 때 실제로보기를 스크롤해야하는지 여부를 감지 할 수 있습니다. stackoverflow.com/a/28813720/6749410
— HirdayGupta

답변:


710

한 textField에서 다른 textField 로의 전환을 처리하지 않는 솔루션은 다음과 같습니다.

 override func viewDidLoad() {
        super.viewDidLoad()
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)            
    }   

func keyboardWillShow(notification: NSNotification) {            
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y -= keyboardSize.height
    }            
}

func keyboardWillHide(notification: NSNotification) {
    self.view.frame.origin.y = 0
}

이 문제를 해결하려면 두 기능 keyboardWillShow/Hide을 다음과 같이 바꾸십시오 .

func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
        if view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

func keyboardWillHide(notification: NSNotification) {
    if view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

스위프트 3.0 편집 :

override func viewDidLoad() {
    super.viewDidLoad()            
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)    
}

@objc func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

SWIFT 4.0 편집 :

override func viewDidLoad() {
    super.viewDidLoad()            
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)    
}

@objc func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

스위프트 4.2 편집 :

override func viewDidLoad() {
    super.viewDidLoad()            
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

56
키보드가있는 동안 사용자가 다른 텍스트 필드를 터치하면 뷰가 더 위로 밀려 검은 영역 (키보드 크기)이 발생합니다. 키보드가 있는지 여부를 추적하는 변수를 사용하여 수정해야합니다. . 예를 들어 keyboardPresent == true이면 뷰 원점 등을 이동하지
— 마십시오.

3
@Matthew Lin은 부울을 사용하므로 keyboardWillShow 함수는 한 번만 작동합니다.
— iluvatar_GR

11
한 가지 제안만으로, 내가했던 것처럼 많이 디버깅 할 필요가 없습니다. 동일한 화면에 여러 개의 uitextfields가있는 경우 키보드 크기가 다를 수 있으므로 (설정에 따라 일부 입력에 대한 제안은 표시되지 않음) self.view.frame.origin.y = 0을 설정하는 것이 좋습니다 키보드를 닫습니다. 예를 들어, 전자 메일 텍스트 필드에 대한 sugeestions를 표시하므로 키보드 크기가 증가하고 암호 필드에 대한 제안이 표시되지 않으므로 키보드 크기가 감소합니다.
— 반단 파텔

36
키보드 크기를 얻을 때가 UIKeyboardFrameEndUserInfoKey아니라 사용해야 UIKeyboardFrameBeginUserInfoKey합니다. 나는 현재 왜 그런지 확신하지 못하지만 전자는 더 일관된 결과를 얻을 것입니다.
— jshapy8

3
교체하십시오 UIKeyboardFrameBeginUserInfoKey로 UIKeyboardFrameEndUserInfoKey. 첫 번째는 키보드의 시작 프레임을 제공하며 때로는 0이되고 두 번째는 키보드의 종료 프레임을 제공합니다.
— Arnab

90

코드가 필요없는 가장 쉬운 방법 :

  1. Spring 애니메이션 프레임 워크를 아직 사용하고 있지 않은 경우 KeyboardLayoutConstraint.swift를 다운로드 하고 파일을 프로젝트에 추가 (끌어다 놓기)하십시오.
  2. 스토리 보드에서보기 또는 텍스트 필드에 대한 맨 아래 제한 조건을 작성하고 제한 조건을 두 번 클릭 한 후 Identity Inspector에서 클래스를 NSLayoutConstraint에서 KeyboardLayoutConstraint로 변경하십시오.
  3. 끝난!

객체는 키보드와 함께 자동으로 위로 움직입니다.


4
하단 제약 조건을 선택하려면 Size Inspector로 이동 한 다음 목록에서 제약 조건을 두 번 클릭하십시오. raywenderlich.com/wp-content/uploads/2015/09/…
— gammachill

3
이것은 나를 위해 완벽하게 작동했습니다. 말 그대로 2 단계 프로세스입니다. 1. KeyboardLayoutConstraint.swift를 추가하십시오. 2. 스토리 보드에서보기 또는 텍스트 필드에 대한 하단 구속 조건을 작성하십시오. 참고 : 제약 조건을 삭제하고보기 또는 텍스트 필드의 맨 아래에 하나의 제약 조건을 추가하고 클래스를 NSLayoutConstraint에서 KeyboardLayoutConstraint로 변경했습니다. 그런 다음 위의 모든보기 / 텍스트 필드 등은 단일 KeyboardLayoutConstraint를 사용하여 해당 항목의 제약 조건을 항목에 연결했으며 결과는 키보드가 나타나거나 사라질 때보기의 모든 항목이 위 / 아래로 이동 한 것입니다.
— Brian

4
제공된 코드는 애니메이션의 길이나 곡선 또는 키보드 크기와 같은 값을 하드 코딩하지 않습니다. 이해하기 쉽습니다.
— miguelSantirso

3
이것은 나를 위해 일하고 있지만 키보드 상단과 scrollView 하단 사이에 50px의 공간이 더 있습니다. 사용중인 안전 영역 하단 제약 조건 때문인지 궁금합니다. 누구든지 이것에 부딪 치나요?
— Clifton Labrum

1
이것은 굉장한 대답이었습니다. 매우 멋진 디자인입니다. 한 가지 제안 : textviews / textfields가 테이블 뷰 셀에있는 경우 사용자가 enter를 클릭하고 다음 텍스트 필드로 이동할 때마다이 제한 조건이있는 뷰가 어색하게 점프하는 것을 알 수 있습니다. 애니메이션을 감싸서 DispatchQueue.main.async {}고칠 수 있습니다. 잘 했어! 엄지 손가락!
— ScottyBlades

68

이 스레드에서 널리 사용되는 답변 중 하나는 다음 코드를 사용합니다.

func keyboardWillShow(sender: NSNotification) {
    self.view.frame.origin.y -= 150
}
func keyboardWillHide(sender: NSNotification) {
    self.view.frame.origin.y += 150
}

뷰를 정적 양만큼 상쇄하는 데 명백한 문제가 있습니다. 한 장치에서는 좋아 보이지만 다른 크기 구성에서는 나빠 보일 것입니다. 키보드 높이를 가져와 오프셋 값으로 사용해야합니다.

다음 은 모든 장치에서 작동 하고 사용자가 입력하는 동안 예측 텍스트 필드를 숨기는 가장자리를 처리 하는 솔루션입니다 .

해결책

아래에서 중요하게, self.view.window를 객체 매개 변수로 전달합니다. 이렇게하면 키와 같은 키보드의 데이터가 제공됩니다!

@IBOutlet weak var messageField: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: self.view.window)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: self.view.window)
}

func keyboardWillHide(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!
    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    self.view.frame.origin.y += keyboardSize.height
}

모든 장치에서 멋지게 보이게하고 사용자가 예측 텍스트 필드를 추가하거나 제거하는 경우를 처리합니다.

func keyboardWillShow(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!
    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    let offset: CGSize = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue.size

    if keyboardSize.height == offset.height {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y -= keyboardSize.height
        })
    } else {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y += keyboardSize.height - offset.height
        })
    }
}

관찰자 제거

불필요한 메시지가 전송되지 않도록보기를 떠나기 전에 관찰자를 제거하는 것을 잊지 마십시오.

override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: self.view.window)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: self.view.window)
}

의견의 질문에 따라 업데이트 :

텍스트 필드가 두 개 이상인 경우 view.frame.origin.y가 0인지 확인할 수 있습니다.

func keyboardWillShow(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!

    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    let offset: CGSize = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue.size

    if keyboardSize.height == offset.height {
        if self.view.frame.origin.y == 0 {
            UIView.animateWithDuration(0.1, animations: { () -> Void in
                self.view.frame.origin.y -= keyboardSize.height
            })
        }
    } else {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y += keyboardSize.height - offset.height
        })
    }
     print(self.view.frame.origin.y)
}

1
여러 텍스트 필드를 다룰 때보기가 계속 위로 올라가고 내려 오지 않습니다.
— Mugunthan Balakrishnan

텍스트 필드를 설명하기 위해 조건을 변경해야합니다
— Dan Beaulieu

덕분에 응답을, 내가 스택 오버플로에이 스레드에서 찾고 있던 해답을 발견 stackoverflow.com/questions/1126726/...
— Mugunthan Balakrishnan

@MugunthanBalakrishnan이 문제를 제기 해 주셔서 감사합니다.
— Dan Beaulieu

안녕하세요 여러분, 버그가 있습니다. viewWillDisappear에서 호출 된 후에는 관찰자가 뷰에서 제거되지 않습니다. 이 줄 "NSNotificationCenter.defaultCenter (). removeObserver (self, name : UIKeyboardWillHideNotification, object : self.view.window)"를 "NSNotificationCenter.defaultCenter (). removeObserver (self, name : UIKeyboardWillHideNotification, object : nil)"로 바꿉니다. 제거됨
— rudald

29

이것을 뷰 컨트롤러에 추가하십시오. 매력처럼 작동합니다. 그냥 값을 조정하십시오.

override func viewDidLoad() {
    super.viewDidLoad()        
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name:NSNotification.Name.UIKeyboardWillShow, object: nil);
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name:NSNotification.Name.UIKeyboardWillHide, object: nil);
}

@objc func keyboardWillShow(sender: NSNotification) {
    self.view.frame.origin.y -= 150
}
@objc func keyboardWillHide(sender: NSNotification) {
    self.view.frame.origin.y += 150
}

이것은 나를 위해 작동합니다. 그러나 약간 육포입니다. 스무디를 위로 올리려면 어떻게해야합니까? 또한 현재 모든 것을 위해 텍스트 필드 중 하나에 만 적용하는 방법이 있습니다. :(
— DannieCoderBoi 2012

2
"자동 레이아웃"에서는 작동하지 않을 수 있으므로 비활성화하십시오.
— Teodor Ciuraru

1
autolayout @Josh와 함께 약간의 펑키 동작이 발생합니다. 실수입니다
— Mike

5
이러지 마! 키보드가 특정 크기라고 가정 할 수 없습니다.
— nielsbot 2016 년

2
keyboardSize를 사용해야합니다. 기기에서 액세서리보기 및 다른 키보드 높이를 사용하면 어떻게됩니까? 분리 된 키보드?
— xtrinch

25

하나의 페이지에서 다른 키보드 및 다른 텍스트보기 / 필드와 함께 작동하도록 답변 중 하나를 약간 개선했습니다.

관찰자 추가 :

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

func keyboardWillHide() {
    self.view.frame.origin.y = 0
}

func keyboardWillChange(notification: NSNotification) {

    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if YOURTEXTVIEW.isFirstResponder {
            self.view.frame.origin.y = -keyboardSize.height
        }
    }
}

관찰자를 제거하십시오.

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}

3
이 솔루션은 허용되는 답변보다 더 효과적입니다. 허용되는 답변은 키보드가 한 번만 버그임을 나타냅니다. :)
— Masih

Xcode 10.1 및 iOS 12에서 작동합니다. 허용 된 답변이 더 이상 유효하지 않습니다.
— zeeshan

이것은 훌륭한 답변입니다. 추가 할 수있는 유일한 것은 최신 장치 (X, XS 등)의 하단 안전 영역을 추적하여 그것을 설명하는 것입니다.
— Munib

@Munib stackoverflow.com/a/54993623/1485230을 참조하십시오. 다른 문제로는보기에 애니메이션이 적용되지 않고 키보드 높이가 변경되지 않는 등의 문제가 있습니다.
— Antzi

내 textField가보기 상단에 있으면 어떻게합니까? 원점 Y = 0 인 텍스트 필드가 있으면 의미합니다 .. ?? 그리고 textField가 올라가서 볼 수 없습니다
— Saifan Nadaf

18

광고 나 판촉 또는 스팸 이 아니라 좋은 해결책입니다. 나는이 질문에 거의 30 가지 답변이 있다는 것을 알고 놀랍습니다. 이 아름다운 GitHub 프로젝트 에 대해 한 번도 언급하지 않아서 당신을 위해 더 잘하고 있습니다. 모든 답변은 뷰를 위로 이동시킵니다. 이 IQKeyboardManager와 관련된 모든 문제를 방금 해결했습니다. 별 13000 개가 있습니다.
swift를 사용하는 경우 podfile에 이것을 추가하십시오.

pod 'IQKeyboardManagerSwift'

그런 다음 AppDelegate.swift 내부에서 import IQKeyboardManagerSwift

import IQKeyboardManagerSwift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

      IQKeyboardManager.shared.enable = true // just add this line

      return true
    }
}

IQKeyboardManager.shared.enable = true활성화하기 위해 라인 추가이
솔루션은 생산을 위해 반드시 필요한 것입니다.


이것은 정말 좋지만 최신 버전은 작동하지 않습니다. 6.2.1을 import IQKeyboardManager사용 IQKeyboardManager.shared().isEnabled = true했으며 AppDelegate 로 가져 와서 사용 했습니다.
— Dhanu K

2
여러 편집 텍스트를 사용할
— 때이 기능이 훌륭하게 작동합니다.

1
이 훌륭한 도서관을 지적 해 주셔서 감사합니다. 이 라이브러리는 마침내 Apple이 솔루션을 제공하지 않은 모든 키보드 관련 넌센스에 대한 최종 답변입니다. 이제 새 프로젝트와 기존의 모든 프로젝트에 사용하고 키보드가 나타나거나 사라지거나 사라지지 않는 방법 또는 숨기는 방법과 겹치는 이유 및 시간이 지남에 따라 문제가 발생했습니다. 하루는 아이폰에 대한 프로그래밍입니다.
— zeeshan

1
나는 다른 솔루션과 마찬가지로 텍스트 필드를 이동시키는 자체 코드를 작성했습니다. 나는 IQKeyboardManager가 매우 우수하다는 것을 알았고 지금부터 그것을 통합 할 것입니다. 프레임 워크가 최신 상태가 아닌 경우를 대비하여 코드를 편리하게 유지합니다.
— TM Lynch

@DhanuK, 방금이 라이브러리를 발견하고 완벽하게 작동하며 어려움이 없습니다. 앱 델리게이트 코드가 IQKeyboardManager.shared.enable = true로 업데이트되었습니다.
— adougies

15

블랙 스크린 오류의 경우 (Swift 4 & 4.2) .

검은 화면 문제를 해결했습니다. 확인 된 해결 방법 탭핑 후 키보드 높이가 변경되어 검은 색 화면이 나타납니다.

UIKeyboardFrameBeginUserInfoKey 대신 UIKeyboardFrameEndUserInfoKey 를 사용해야합니다.

var isKeyboardAppear = false

override func viewDidLoad() {
    super.viewDidLoad() 
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

@objc func keyboardWillShow(notification: NSNotification) {
    if !isKeyboardAppear {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            if self.view.frame.origin.y == 0{
                self.view.frame.origin.y -= keyboardSize.height
            }
        }
        isKeyboardAppear = true
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if isKeyboardAppear {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            if self.view.frame.origin.y != 0{
                self.view.frame.origin.y += keyboardSize.height
            }
        }
         isKeyboardAppear = false
    }
}

탭 막대가 있으면 작동하지 않습니다. Tabbar 높이를 계산해야합니다. 그렇지 않으면 키보드와보기 사이에 검은 화면 간격이 생깁니다.
— Ankur Lahiry

키보드가 iPhone X 이상에 있던 검은 부분은 고정되지 않습니다. 그리고 키보드가 나타나고 사라질 때마다 메인 뷰가 계속 아래로 미끄러집니다.
— Edison

14

모든 답변이 키보드 높이의 값으로보기 자체를 움직이는 것으로 보입니다. 글쎄, 나는 정교한 답을 가지고 있는데, 그것은 당신이 제약을 사용한다면 유용 할 수 있습니다.autolayout , 제약 값 (예 : 하단 또는 상단 제약 조건)을 미리 정의 된 값으로 변경하거나 키보드 크기 값을 사용할 .

이 예제에서는 텍스트 필드에서 Bottom Layout View까지의 Bottom constraint를 초기 값 175로 사용합니다.

@IBOutlet weak var bottomConstraint: NSLayoutConstraint!

override func viewDidLoad() {
    super.viewDidLoad()        
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil);
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil);
}

func keyboardWillShow(notification: NSNotification) {
    //To retrieve keyboard size, uncomment following line
    //let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
    bottomConstraint.constant = 260
    UIView.animateWithDuration(0.3) {
        self.view.layoutIfNeeded()
    }
}

func keyboardWillHide(notification: NSNotification) {
    //To retrieve keyboard size, uncomment following line
    //let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
    bottomConstraint.constant = 175
    UIView.animateWithDuration(0.3) {
        self.view.layoutIfNeeded()
    }
}

안녕하세요, TableView를 포함하는 뷰에 배치했을 때 왜 이것이 작동하지 않는지 말씀해 주시겠습니까? CollectionView가 포함 된 동일한 시나리오에서 제대로 작동합니다.
— elarcoiris

9

KeyboardWillHideNotification을 정의하는 방법이 약간 변경되었습니다.

이 솔루션은 Swift 4.2에서 작동합니다 .

NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)


@objc func keyboardWillShow(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        self.view.frame.origin.y -= keyboardSize.height
    }
}

@objc func keyboardWillHide(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        self.view.frame.origin.y += keyboardSize.height
    }
}

2
내 textField가보기 상단에 있으면 어떻게합니까? 원점 Y = 0 인 텍스트 필드가 있으면 의미합니다 .. ?? 그리고 textField가 올라가서 볼 수 없습니다
— Saifan Nadaf

7

스위프트 5.0 :

4-5 시간의 싸움 후 나는 매력처럼 작동하는 간단한 코드로 UIViewController의 간단한 확장 기능을 사용했습니다.

* 텍스트 필드가 키보드 위에있을 때보기가 움직이지 않아야합니다.

* 상수 값을 NSLayoutConstraint로 설정할 필요가 없습니다.

* 타사 라이브러리 불필요

* 애니메이션 코드 불필요

* 테이블 뷰에서도 작동

* 이것은 자동 레이아웃 / 자동 크기 조정에서 작동합니다

extension UIViewController {
    func addKeyboardObserver() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardNotifications(notification:)),
                                               name: UIResponder.keyboardWillChangeFrameNotification,
                                               object: nil)
    }

    func removeKeyboardObserver(){
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    }

    // This method will notify when keyboard appears/ dissapears
    @objc func keyboardNotifications(notification: NSNotification) {

        var txtFieldY : CGFloat = 0.0  //Using this we will calculate the selected textFields Y Position
        let spaceBetweenTxtFieldAndKeyboard : CGFloat = 5.0 //Specify the space between textfield and keyboard


        var frame = CGRect(x: 0, y: 0, width: 0, height: 0)
        if let activeTextField = UIResponder.currentFirst() as? UITextField ?? UIResponder.currentFirst() as? UITextView {
            // Here we will get accurate frame of textField which is selected if there are multiple textfields
            frame = self.view.convert(activeTextField.frame, from:activeTextField.superview)
            txtFieldY = frame.origin.y + frame.size.height
        }

        if let userInfo = notification.userInfo {
            // here we will get frame of keyBoard (i.e. x, y, width, height)
            let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
            let keyBoardFrameY = keyBoardFrame!.origin.y
            let keyBoardFrameHeight = keyBoardFrame!.size.height

            var viewOriginY: CGFloat = 0.0
            //Check keyboards Y position and according to that move view up and down
            if keyBoardFrameY >= UIScreen.main.bounds.size.height {
                viewOriginY = 0.0
            } else {
                // if textfields y is greater than keyboards y then only move View to up
                if txtFieldY >= keyBoardFrameY {

                    viewOriginY = (txtFieldY - keyBoardFrameY) + spaceBetweenTxtFieldAndKeyboard

                    //This condition is just to check viewOriginY should not be greator than keyboard height
                    // if its more than keyboard height then there will be black space on the top of keyboard.
                    if viewOriginY > keyBoardFrameHeight { viewOriginY = keyBoardFrameHeight }
                }
            }

            //set the Y position of view
            self.view.frame.origin.y = -viewOriginY
        }
    }
}

선택한 TextField를 가져 오려면이 UIResponder 확장을 추가하십시오.

extension UIResponder {

    static weak var responder: UIResponder?

    static func currentFirst() -> UIResponder? {
        responder = nil
        UIApplication.shared.sendAction(#selector(trap), to: nil, from: nil, for: nil)
        return responder
    }

    @objc private func trap() {
        UIResponder.responder = self
    }
}

그런 다음 모든 ViewController에서 이것을 사용하십시오.

   override func viewWillAppear(_ animated: Bool) {
        self.addKeyboardObserver()
    }

    override func viewWillDisappear(_ animated: Bool) {
        self.removeKeyboardObserver()
    }

  • 이 알림을 등록하십시오 func viewWillAppear(_ animated: Bool)

  • 이 알림을 등록 취소 func viewWillDisappear(_ animated:Bool)

    여기 데모 다운로드


이것은 최상의 솔루션처럼 보였지만 몇 가지 버그가 있습니다. 1, 텍스트 필드가 위로 이동하지만 입력을 시작하면 조금 더 올라갑니다. 2, textField를 입력 할 때 가로로 때때로 왼쪽으로 이동합니다.
— 대런

@Darren 나는이 버그를 알아 내려고 노력하고 있지만 찾지 못했습니다.이 버그가있는 곳을 알려면 어떤 버전 / 장치를 의미하는지 알 수 있습니까?
— 사이판 나다 프

6

Swift 3의 경우 모든 View Controller에서 지속적인 동작이 필요했기 때문에 UIViewController 하위 클래스를 만들었습니다.

class SomeClassVC: UIViewController {

  //MARK: - Lifecycle
  override func viewDidLoad() {
    super.viewDidLoad()

    addKeyboardObservers()
  }

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    removeKeyboardObservers()
  }

  //MARK: - Overrides
  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    view.endEditing(true)
  }

  //MARK: - Help
  func addKeyboardObservers() {
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
  }

  func removeKeyboardObservers() {
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: self.view.window)
  }

  func keyboardWillShow(notification: NSNotification) {
    let keyboardHeight = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.height
    UIView.animate(withDuration: 0.1, animations: { () -> Void in
      self.view.window?.frame.origin.y = -1 * keyboardHeight!
      self.view.layoutIfNeeded()
    })
  }

  func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.1, animations: { () -> Void in
      self.view.window?.frame.origin.y = 0
      self.view.layoutIfNeeded()
    })
  }

  func resignTextFieldFirstResponders() {
    for textField in self.view.subviews where textField is UITextField {
      textField.resignFirstResponder()
    }
  }

  func resignAllFirstResponders() {
      view.endEditing(true)
  }
}

Pavle의 솔루션에서 영감을 얻어 키보드를 사용 가능한 남은 공간의 일정 비율만큼 자동으로 높이고 올바른 레이아웃을 위해 초점을 맞춘 필드를 재귀 적으로 찾을 수 있도록 업그레이드했습니다. 여기를 잡아 : gist.github.com/noordawod/24d32b2ce8363627ea73d7e5991009a0
— 누르 Dawod

내 탭 표시 줄도 창 위로 올라갑니다! :(
— Alfi

6

검증 된 답변은 텍스트 필드 위치를 고려 하지 않고 버그가 있습니다 (이중 변위, 절대 기본 위치로 돌아 가지 않음, texfield가 뷰의 상단에 있더라도 변위 ...)

아이디어는 다음과 같습니다

  • 초점 TextField 절대 Y 위치를 얻으려면
  • 키보드 높이를 얻기 위해
  • ScreenHeight를 얻으려면
  • 그런 다음 키보드 위치와 텍스트 필드 사이의 거리를 계산하십시오 (<0-> 경우 뷰 위로 이동)
  • UIView.frame.origin.y-= .. 대신 UIView.transform을 사용하려면 UIView.transform = .identity를 사용하여 원래 위치로 돌아 오는 것이 더 쉽습니다.

그런 다음 키보드 바로 위에 초점을 맞춘 texField를 갖도록 필요한 경우와 특정 변위의 경우에만 뷰를 이동할 수 있습니다.

코드는 다음과 같습니다.

스위프트 4

class ViewController: UIViewController, UITextFieldDelegate {

var textFieldRealYPosition: CGFloat = 0.0

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(VehiculeViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(VehiculeViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)

  // Delegate all textfields

}


@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        let distanceBetweenTextfielAndKeyboard = self.view.frame.height - textFieldRealYPosition - keyboardSize.height
        if distanceBetweenTextfielAndKeyboard < 0 {
            UIView.animate(withDuration: 0.4) {
                self.view.transform = CGAffineTransform(translationX: 0.0, y: distanceBetweenTextfielAndKeyboard)
            }
        }
    }
}


@objc func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.4) {
        self.view.transform = .identity
    }
}


func textFieldDidBeginEditing(_ textField: UITextField) {
  textFieldRealYPosition = textField.frame.origin.y + textField.frame.height
  //take in account all superviews from textfield and potential contentOffset if you are using tableview to calculate the real position
}

}


아주 좋아요! viewDidLoad에는 "ViewController"대신 "VehiculeViewController"가 있습니다.
— 르네

훨씬 더 완전하고 유용한 답변. 감사합니다! 키보드 크기가 일관된 크기를 제공하기 때문에 키보드 검사를 다음과 같이 호출하는 것이 좋습니다 ......... 키보드 크기 = (notification.userInfo? [UIResponder.keyboardFrameEndUserInfoKey] as? NSValue) ?. cgRectValue .크기
— Ben

4

다른 답변은 뷰에서 상단의 일부를 자르는 것과 관련이 있음을 알았습니다. 내용을 자르지 않고 단순히 뷰의 크기를 조정하려면이 방법을 시도하십시오 :)

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.setTranslatesAutoresizingMaskIntoConstraints(true)
        self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.height - keyboardSize.height)
    }
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.collectionView.setTranslatesAutoresizingMaskIntoConstraints(false)
        self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.height + keyboardSize.height)
    }
}

4

초보자를위한 내 두 센트 : 위의 샘플에서 누군가가 좌표를 변경하고 다른 것은 "자동 크기 조정 마스크"및 기타 제약 조건을 변경합니다.

애플이 말했듯이이 3 가지 유형의 논리를 섞지 마십시오. 스토리 보드에 제약이있는 경우 x / y를 변경하지 마십시오. 확실히 작동하지 않습니다.


4

따라서 다른 답변 중 어느 것도 올바르게 이해하지 못하는 것 같습니다.

iOS의 올바른 행동 키보드는 다음과 같아야합니다.

  • 키보드 크기가 변경되면 자동으로 크기 조정 (YES IT CAN)
  • 키보드와 같은 속도로 애니메이션
  • 키보드와 동일한 곡선을 사용하여 애니메이션
  • 안전 지역을 존중하십시오.
  • iPad / 도킹 해제 모드에서도 작동

내 코드 NSLayoutConstraint는@IBOutlet

@IBOutlet private var bottomLayoutConstraint: NSLayoutConstraint!

변환, 뷰 오프셋 등을 사용할 수도 있습니다. 제약 조건을 사용하면 더 쉽다고 생각합니다. 제약 조건을 맨 아래로 설정하여 작동합니다. 상수가 0이 아니거나 맨 아래가 아닌 경우 코드를 변경해야 할 수도 있습니다.

코드는 다음과 같습니다.

// In ViewDidLoad
    NotificationCenter.default.addObserver(self, selector: #selector(?MyViewController.keyboardDidChange), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)


@objc func keyboardDidChange(notification: Notification) {
    let userInfo = notification.userInfo! as [AnyHashable: Any]
    let endFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
    let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber
    let animationCurve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as! NSNumber
    bottomLayoutConstraint.constant = view.frame.height - endFrame.origin.y - view.safeAreaInsets.bottom // If your constraint is not defined as a safeArea constraint you might want to skip the last part.
    // Prevents iPad undocked keyboard.
    guard endFrame.height != 0, view.frame.height == endFrame.height + endFrame.origin.y else {
        bottomLayoutConstraint.constant = 0
        return
    }
    UIView.setAnimationCurve(UIView.AnimationCurve(rawValue: animationCurve.intValue)!)
    UIView.animate(withDuration: animationDuration.doubleValue) {
        self.view.layoutIfNeeded()
        // Do additional tasks such as scrolling in a UICollectionView
    }
}

3

키보드를 열 때 모든 Guy의 업데이트 테이블 뷰 높이에 대한 100 % 완벽한 답변

스위프트 4.2

   override func viewDidLoad() {
      super.viewDidLoad()
      NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)

      NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
   }

   @objc func keyboardWillShow(notification: NSNotification) {
    if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {

        var userInfo = notification.userInfo!
        var keyboardFrame:CGRect = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        keyboardFrame = self.view.convert(keyboardFrame, from: nil)

        var contentInset:UIEdgeInsets = self.tbl.contentInset
          contentInset.bottom = keyboardFrame.size.height
          self.tbl.contentInset = contentInset
    }
}

   @objc func keyboardWillHide(notification: NSNotification) {
    if ((notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
        let contentInset:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        self.tbl.contentInset = contentInset
    }
}

스위프트 3.2

    override func viewDidLoad() {
          super.viewDidLoad()

           NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)

           NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }
    func keyboardWillShow(notification: NSNotification) {
         if ((notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
         //self.view.frame.origin.y -= keyboardSize.height
         var userInfo = notification.userInfo!
         var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
          keyboardFrame = self.view.convert(keyboardFrame, from: nil)

          var contentInset:UIEdgeInsets = self.tbl.contentInset
          contentInset.bottom = keyboardFrame.size.height
          self.tbl.contentInset = contentInset

       }
    }

    func keyboardWillHide(notification: NSNotification) {
         if ((notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
         let contentInset:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
         self.tbl.contentInset = contentInset
         }
    }

이것이 가장 좋은 대답입니다. TBL이있는 tableView를해야하며, 좀 패딩 추가 : contentInset.bottom = keyboardFrame.size.height를 + 10
— iphaaw

2

대한 스위프트 3

func textFieldDidBeginEditing(_ textField: UITextField) { // became first responder

    //move textfields up
    let myScreenRect: CGRect = UIScreen.main.bounds
    let keyboardHeight : CGFloat = 216

    UIView.beginAnimations( "animateView", context: nil)
    var movementDuration:TimeInterval = 0.35
    var needToMove: CGFloat = 0

    var frame : CGRect = self.view.frame
    if (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height > (myScreenRect.size.height - keyboardHeight - 30)) {
        needToMove = (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height) - (myScreenRect.size.height - keyboardHeight - 30);
    }

    frame.origin.y = -needToMove
    self.view.frame = frame
    UIView.commitAnimations()
}

func textFieldDidEndEditing(_ textField: UITextField) {
    //move textfields back down
    UIView.beginAnimations( "animateView", context: nil)
    var movementDuration:TimeInterval = 0.35
    var frame : CGRect = self.view.frame
    frame.origin.y = 0
    self.view.frame = frame
    UIView.commitAnimations()
}

2

스위프트 4 :

키보드를 숨기면 페이지의 맨 아래로 부분적으로 만 뷰가 반환되지 않는 가장 널리 사용되는 답변에 문제가있었습니다. 이것은 나를 위해 일했습니다 (Swift 4의 경우 + 업데이트).

override func viewDidLoad() {
    super.viewDidLoad()
    self.hideKeyboardWhenTappedAround()
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0{
            self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y != 0{
            self.view.frame.origin.y = 0
        }
    }
}

내 textField가보기 상단에 있으면 어떻게합니까? 원점 Y = 0 인 텍스트 필드가 있으면 의미합니다 .. ?? 그리고 textField가 올라가서 볼 수 없습니다
— Saifan Nadaf

2

@Boris 답변과 유사하지만 Swift 5에서는 :

override func viewDidLoad() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

@IBAction func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

@IBAction func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

1

여기 내 해결책이 있습니다 (실제로이 코드는 뷰에 텍스트 필드가 거의없는 경우에 대한 것이며, 하나의 텍스트 필드가있는 경우에도 작동합니다)

class MyViewController: UIViewController, UITextFieldDelegate {

@IBOutlet weak var firstTextField: UITextField!
@IBOutlet weak var secondTextField: UITextField!

var activeTextField: UITextField!
var viewWasMoved: Bool = false


override func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PrintViewController.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PrintViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}

override func viewDidDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func textFieldDidBeginEditing(textField: UITextField) {
    self.activeTextField = textField
}

func textFieldDidEndEditing(textField: UITextField) {
    self.activeTextField = nil
}

func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}


func keyboardWillShow(notification: NSNotification) {

    let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()

    var aRect: CGRect = self.view.frame
    aRect.size.height -= keyboardSize!.height

    let activeTextFieldRect: CGRect? = activeTextField?.frame
    let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.origin

    if (!CGRectContainsPoint(aRect, activeTextFieldOrigin!)) {
        self.viewWasMoved = true
        self.view.frame.origin.y -= keyboardSize!.height
    } else {
        self.viewWasMoved = false
    }
}

func keyboardWillHide(notification: NSNotification) {
    if (self.viewWasMoved) {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            self.view.frame.origin.y += keyboardSize.height
        }
    }
}


keyboardwillshow의 조건을 변경하는 경우 (CGRectContainsPoint (aRect, newOrgin) && self.viewWasMoved!!!), 등
— KingofBliss

프레임을 재설정 할 때 self.viewWasMoved = false 추가
— KingofBliss

1

스위프트 3 업데이트 ...

다른 사람들이 말했듯이 컨트롤러의 viewDidLoad () 메소드에 알림 관찰자를 추가해야합니다.

NotificationCenter.default.addObserver(forName: .UIKeyboardWillShow, object: nil, queue: nil)
    { notification in
    self.keyboardWillShow(notification)
    }

NotificationCenter.default.addObserver(forName: .UIKeyboardWillHide, object: nil, queue: nil)
    { notification in
    self.keyboardWillHide(notification)
    }

NotificationCenter.default.addObserver(forName: .UIKeyboardDidShow, object: nil, queue: nil)
    { _ in
    self.enableUserInteraction()
    }

NotificationCenter.default.addObserver(forName: .UIKeyboardDidHide, object: nil, queue: nil)
    { _ in
    self.enableUserInteraction()
    }

적절한 경우 관찰자를 제거해야합니다 (viewWillDisappear () 메소드에서 수행).

NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidHide, object: nil)

그런 다음 show 및 hide 메소드를 구현하십시오. 앱이 상호 작용 이벤트를 무시하도록 지시하는 행을 확인하십시오 (beginIgnoringInteractionEvents). 이것이 없으면 사용자가 필드 또는 스크롤보기를 탭하고 두 번째로 시프트가 발생하여 UI 결함이 끔찍할 수 있기 때문에 중요합니다. 키보드 표시 및 숨기기 전에 상호 작용 이벤트를 무시하면 다음을 방지 할 수 있습니다.

func keyboardWillShow(notification: Notification)
    {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
        {
        UIApplication.shared.beginIgnoringInteractionEvents()
        self.view.frame.origin.y -= keyboardSize.height
        // add this line if you are shifting a scrollView, as in a chat application
        self.timelineCollectionView.contentInset.top += keyboardSize.height
        }
    }

func keyboardWillHide(notification: Notification)
    {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
        {
        UIApplication.shared.beginIgnoringInteractionEvents()
        self.view.frame.origin.y += keyboardSize.height
        // add this line if you are shifting a scrollView, as in a chat application
        self.timelineCollectionView.contentInset.top -= keyboardSize.height
        }
    }

마지막으로 사용자 상호 작용을 다시 활성화하십시오 (키보드 didShow 또는 didHide 후에이 메소드가 실행됨을 기억하십시오).

func enableUserInteraction()
    {
    UIApplication.shared.endIgnoringInteractionEvents()
    }

1

스위프트 3 코드

var activeField: UITextField?

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(ProfileViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ProfileViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

func textFieldDidBeginEditing(_ textField: UITextField){
    activeField = textField
}

func textFieldDidEndEditing(_ textField: UITextField){
    activeField = nil
}

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if (self.activeField?.frame.origin.y)! >= keyboardSize.height {
            self.view.frame.origin.y = keyboardSize.height - (self.activeField?.frame.origin.y)!
        } else {
            self.view.frame.origin.y = 0
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    self.view.frame.origin.y = 0
}

1

동일한 VC에 두 개 이상의 텍스트 필드가 있고 사용자가 keyboardWillHide 함수를 호출하지 않고 두 필드 중 하나를 탭한 다음 다른 필드를 탭하면보기가 한 번 더 위로 올라갑니다. 당신은 키보드, 키보드의 높이가있는 빈 공간, 그리고 내가 편집 한 답변의 코드를 사용하여보기를 갖게됩니다 :

override func viewDidLoad() {       
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
}

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y -= keyboardSize.height
    }
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y += keyboardSize.height
    }
}

이 문제를 해결하려면 다음 두 기능 "KeyboardWillShow / Hide"를 다음과 같이 바꾸십시오.

func keyboardWillShow(notification: NSNotification) {
 if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
    if view.frame.origin.y == 0{
        self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        if view.frame.origin.y != 0 {
            self.view.frame.origin.y += keyboardSize.height
        }
    }
}

내 textField가보기 상단에 있으면 어떻게합니까? 원점 Y = 0 인 텍스트 필드가 있으면 의미합니다 .. ?? 그리고 textField가 올라가서 볼 수 없습니다
— Saifan Nadaf

1

@Boris의 솔루션은 매우 좋지만 때로는보기가 손상 될 수 있습니다.

완벽한 정렬을 위해 아래 코드를 사용하십시오.

override func viewDidLoad() {
super.viewDidLoad()            
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)}

기능 :

@objc func keyboardWillShow(notification: NSNotification) {        
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
    if self.view.frame.origin.y == 0{
        self.view.frame.origin.y -= keyboardSize.height
    }
}}    

과,

@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
    if self.view.frame.origin.y != 0{
        self.view.frame.origin.y = 0 
    }
} }

0

이 비디오 튜토리얼이 최고입니다. 7 분 정도 걸리면 이해가 될 것입니다. 여러 텍스트 필드가 있고 특정 텍스트 필드를 누를 때 스크롤보기가 "x"픽셀 단위로 이동하기를 원하는 간단한 솔루션입니다.

https://youtu.be/VuiPGJOEBH4

이 단계들 :

-보기의 가장자리로 제한된 스크롤보기 내에 모든 텍스트 필드를 배치하십시오.

-모든 텍스트 필드를 연결하고 뷰 컨트롤러에 대리자로 뷰를 스크롤하십시오.

모든 텍스트 필드를 연결하고 IBOutlet으로 스크롤보기.

class ViewController: UIViewController, UITextFieldDelegate {

-클래스에 UITextFieldDelegate 프로토콜 추가

@IBOutlet var stateAddress: UITextField!
@IBOutlet var zipAddress: UITextField!
@IBOutlet var phoneNumber: UITextField!
@IBOutlet var vetEmailAddress: UITextField!    
@IBOutlet weak var scrollView: UIScrollView!

빠른 파일에 UITextFieldDelegate 메소드를 추가하십시오.

func textFieldShouldReturn(textField: UITextField) -> Bool {

    textField.resignFirstResponder()
    return true
}


func textFieldDidBeginEditing(textField: UITextField) {

    if (textField == self.stateAddress) {
        scrollView.setContentOffset(CGPointMake(0, 25), animated: true)
    }
    else if (textField == self.zipAddress) {
        scrollView.setContentOffset(CGPointMake(0, 57), animated: true)
    }
    else if (textField == self.phoneNumber) {
        scrollView.setContentOffset(CGPointMake(0, 112), animated: true)
    }
    else if (textField == self.vetEmailAddress) {
        scrollView.setContentOffset(CGPointMake(0, 142), animated: true)
    }
}

func textFieldDidEndEditing(textField: UITextField) {

    scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
}

첫 번째 방법은 키보드의 리턴 버튼을 활성화하여 키보드를 닫습니다. 두 번째는 특정 텍스트 필드를 탭하고 스크롤보기가 스크롤되는 거리의 y 오프셋을 설정하는 경우입니다 (광산은 내보기 컨트롤러의 y 위치를 기준으로합니다 25,57,112,142). 마지막은 키보드에서 멀어지면 스크롤보기가 원래 위치로 돌아갑니다.

이 방법으로 뷰 픽셀을 완벽하게 만들었습니다!


0

이 기능은 Ios에 내장되어 있지만 외부에서 수행해야합니다.
아래 코드 삽입
* textField가 키보드 아래에있을 때보기 이동,
* textField가 키보드 위에있을 때보기 이동 안 함
* 필요할 때 키보드 높이를 기준으로보기 이동
이것은 모든 경우에 작동하고 테스트되었습니다.

import UIKit

class NamVcc: UIViewController, UITextFieldDelegate
{
    @IBOutlet weak var NamTxtBoxVid: UITextField!

    var VydTxtBoxVar: UITextField!
    var ChkKeyPadDspVar: Bool = false
    var KeyPadHytVal: CGFloat!

    override func viewDidLoad()
    {
        super.viewDidLoad()

        NamTxtBoxVid.delegate = self
    }

    override func viewWillAppear(animated: Bool)
    {
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: #selector(TdoWenKeyPadVyd(_:)),
            name:UIKeyboardWillShowNotification,
            object: nil);
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: #selector(TdoWenKeyPadHyd(_:)),
            name:UIKeyboardWillHideNotification,
            object: nil);
    }

    func textFieldDidBeginEditing(TxtBoxPsgVar: UITextField)
    {
        self.VydTxtBoxVar = TxtBoxPsgVar
    }

    func textFieldDidEndEditing(TxtBoxPsgVar: UITextField)
    {
        self.VydTxtBoxVar = nil
    }

    func textFieldShouldReturn(TxtBoxPsgVar: UITextField) -> Bool
    {
        self.VydTxtBoxVar.resignFirstResponder()
        return true
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
    {
        view.endEditing(true)
        super.touchesBegan(touches, withEvent: event)
    }

    func TdoWenKeyPadVyd(NfnPsgVar: NSNotification)
    {
        if(!self.ChkKeyPadDspVar)
        {
            self.KeyPadHytVal = (NfnPsgVar.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().height

            var NonKeyPadAraVar: CGRect = self.view.frame
            NonKeyPadAraVar.size.height -= self.KeyPadHytVal

            let VydTxtBoxCenVal: CGPoint? = VydTxtBoxVar?.frame.origin

            if (!CGRectContainsPoint(NonKeyPadAraVar, VydTxtBoxCenVal!))
            {
                self.ChkKeyPadDspVar = true
                UIView.animateWithDuration(1.0,
                    animations:
                    { self.view.frame.origin.y -= (self.KeyPadHytVal)},
                    completion: nil)
            }
            else
            {
                self.ChkKeyPadDspVar = false
            }
        }

    }

    func TdoWenKeyPadHyd(NfnPsgVar: NSNotification)
    {
        if (self.ChkKeyPadDspVar)
        {
            self.ChkKeyPadDspVar = false
            UIView.animateWithDuration(1.0,
                animations:
                { self.view.frame.origin.y += (self.KeyPadHytVal)},
                completion: nil)
        }
    }

    override func viewDidDisappear(animated: Bool)
    {
        super.viewWillDisappear(animated)
        NSNotificationCenter.defaultCenter().removeObserver(self)
        view.endEditing(true)
        ChkKeyPadDspVar = false
    }
}

| :: | 때로는보기가 다운되는 경우 높이 +/- 150을 사용하십시오.

    NonKeyPadAraVar.size.height -= self.KeyPadHytVal + 150

    { self.view.frame.origin.y -= self.KeyPadHytVal  - 150},
                    completion: nil)

    { self.view.frame.origin.y += self.KeyPadHytVal  - 150},
                completion: nil)

0
func keyboardWillShow(notification: NSNotification) {

    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y = self.view.frame.height - (self.view.frame.height + keyboardSize.height)
    }

}

func keyboardWillHide(notification: NSNotification) {
        self.view.frame.origin.y = 0
}

더 안정적이어야합니다


0
 override func viewWillAppear(animated: Bool)
 {
 super.viewWillAppear(animated)

 NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
 NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)

 }

 // MARK: - keyboard
 func keyboardWillShow(notification: NSNotification) 
{

if let userInfo = notification.userInfo {
if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
let contentInsets = self.tblView.contentInset as UIEdgeInsets
self.tblView.contentInset = UIEdgeInsets(top: contentInsets.top, left: contentInsets.left, bottom: keyboardSize.height, right:contentInsets.right)
                    // ...
                } else {
                    // no UIKeyboardFrameBeginUserInfoKey entry in userInfo
                }
            } else {
                // no userInfo dictionary in notification
            }
        }

func keyboardWillHide(notification: NSNotification) 
{
let contentInsets = self.tblView.contentInset as UIEdgeInsets
self.tblView.contentInset = UIEdgeInsets(top: contentInsets.top, left: contentInsets.left, bottom: 0, right:contentInsets.right)
 }

0

클릭 한 UITextField에서보기 위해 다음 코드를 사용하십시오.

func textFieldDidBeginEditing(textField: UITextField) {
    ViewUpanimateMoving(true, upValue: 100)
}
func textFieldDidEndEditing(textField: UITextField) {
    ViewUpanimateMoving(false, upValue: 100)
}
func ViewUpanimateMoving (up:Bool, upValue :CGFloat){
    var durationMovement:NSTimeInterval = 0.3
    var movement:CGFloat = ( up ? -upValue : upValue)
    UIView.beginAnimations( "animateView", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(durationMovement)
    self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
    UIView.commitAnimations()
}

0

문제를 단순화하기 위해 코코아 포드를 만들었습니다.

https://github.com/xtrinch/KeyboardLayoutHelper

사용 방법:

자동 레이아웃 맨 아래 제약 조건을 만들고 KeyboardLayoutConstraint 클래스를 제공하십시오. 모듈에서 KeyboardLayoutConstraint 하면 포드는 키보드가 나타나고 사라지는 것을 수용하기 위해 키보드를 늘리는 데 필요한 작업을 수행합니다. 사용 방법에 대한 예제 프로젝트 예제를 참조하십시오 (두 가지 : scrollView 내부의 textFields 및 두 개의 기본보기가있는 세로 중심의 textFields-로그인 및 등록).

하단 레이아웃 제약 조건은 컨테이너보기, textField 자체, 무엇이든 지정할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.