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
교체하십시오 UIKeyboardFrameBeginUserInfoKeyUIKeyboardFrameEndUserInfoKey. 첫 번째는 키보드의 시작 프레임을 제공하며 때로는 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.