Di chuyển chế độ xem bằng bàn phím bằng Swift


278

Tôi có một ứng dụng có trường văn bản ở nửa dưới của chế độ xem. Điều này có nghĩa là khi tôi đi nhập vào trường văn bản, bàn phím sẽ bao phủ trường văn bản.

Làm thế nào tôi có thể di chuyển khung nhìn lên trên trong khi gõ để tôi có thể thấy những gì tôi đang gõ và sau đó di chuyển nó trở lại vị trí ban đầu khi bàn phím biến mất?

Tôi đã tìm kiếm khắp nơi nhưng tất cả các giải pháp dường như đều có trong Obj-C mà tôi chưa thể chuyển đổi hoàn toàn.

Mọi sự trợ giúp sẽ rất được trân trọng.


Cách tốt nhất để làm điều này là đặt nội dung của bạn vào trong UIScrollView , sau đó điều chỉnh thuộc tính contentInset của chế độ xem cuộn theo chiều cao của bàn phím khi nó được hiển thị. Tuyệt đối không giả sử chiều cao bàn phím - sử dụng giá trị từ thông báo "bàn phím sẽ hiển thị".
nielsbot

1
Trên thực tế, các tài liệu của Apple cho bạn biết cách thực hiện việc này, trong phần "Quản lý bàn phím": developer.apple.com/l
Library / ios / document /StringsTextFonts / Lỗi

11
Tôi nghĩ rằng tất cả các câu trả lời dưới đây không xem xét một trường hợp: nếu bạn có nhiều trường văn bản và một số trong số chúng nằm ở trên cùng của màn hình thì sao? Bất cứ khi nào người dùng chạm vào trường văn bản đó, nó sẽ vượt ra ngoài màn hình, tôi khá chắc chắn câu trả lời chính xác sẽ phát hiện xemit is actually needed to scroll view up when keyboard appears
theDC

Câu trả lời này có thể phát hiện xem có thực sự cần thiết để cuộn chế độ xem khi bàn phím xuất hiện hay không bằng cách kiểm tra xem trường văn bản hiện đang được chỉnh sửa có chiếm cùng không gian với bàn phím hay không: stackoverflow.com/a/28813720/6749410
HirdayGupta

Câu trả lời:


709

Đây là một giải pháp, không cần xử lý chuyển đổi từ một textField sang một văn bản khác:

 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
}

Để giải quyết điều này, thay thế hai chức năng keyboardWillShow/Hidebằng:

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
    }
}

EDIT CHO SWift 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
    }
}

EDIT CHO 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
    }
}

CHỈNH SỬA ĐỔI 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
Nếu người dùng chạm vào trường văn bản khác trong khi bàn phím có mặt, chế độ xem sẽ bị đẩy lên cao hơn gây ra một vùng màu đen (kích thước của bàn phím) - chúng ta cần khắc phục điều đó bằng cách có một biến theo dõi nếu bàn phím có mặt hay không . ví dụ: nếu keyboardPftime == true thì không di chuyển gốc xem v.v.
jonprasetyo

3
@Matthew Lin sử dụng boolean để các chức năng bàn phímWillShow và ẩn chỉ hoạt động một lần
iluvatar_GR

11
Chỉ cần một đề nghị, để bạn không phải gỡ lỗi nhiều như tôi đã làm. Nếu bạn có nhiều uitextfield trên cùng một màn hình, kích thước bàn phím có thể thay đổi (nó không hiển thị đề xuất cho một số đầu vào dựa trên cài đặt của bạn), vì vậy, nên đặt self.view.frame.origin.y = 0, mọi lúc bạn gạt bỏ bàn phím. Ví dụ: nó sẽ hiển thị các mức độ phù hợp cho trường văn bản email của bạn, vì vậy kích thước bàn phím sẽ tăng lên và nó sẽ không hiển thị các đề xuất cho trường mật khẩu, vì vậy kích thước bàn phím sẽ giảm.
Vandan Patel

36
Bạn cần sử dụng UIKeyboardFrameEndUserInfoKeyhơn là UIKeyboardFrameBeginUserInfoKeykhi lấy kích thước bàn phím. Tôi không chắc tại sao vào lúc này, nhưng trước đây sẽ mang lại kết quả phù hợp hơn.
jshacco8

3
Hãy thay thế UIKeyboardFrameBeginUserInfoKeybằng UIKeyboardFrameEndUserInfoKey. Cái đầu tiên cho khung bắt đầu của bàn phím, đôi khi bằng 0, trong khi cái thứ hai cho khung kết thúc của bàn phím.
Arnab

90

Cách dễ nhất mà thậm chí không yêu cầu bất kỳ mã nào:

  1. Tải xuống KeyboardLayoutConstraint.swift và thêm (kéo và thả) tệp vào dự án của bạn, nếu bạn chưa sử dụng khung hoạt hình Spring.
  2. Trong bảng phân cảnh của bạn, hãy tạo một ràng buộc dưới cùng cho Chế độ xem hoặc Văn bản, chọn ràng buộc (bấm đúp vào nó) và trong Trình kiểm tra danh tính, thay đổi lớp của nó từ NSLayoutConstraint thành KeyboardLayoutConstraint.
  3. Làm xong!

Đối tượng sẽ tự động di chuyển lên bằng bàn phím, đồng bộ hóa.


4
Để chọn ràng buộc dưới cùng, bạn cũng có thể truy cập Size Inspector, sau đó nhấp đúp vào ràng buộc trong danh sách - raywenderlich.com/wp-content/uploads/2015/09/
gammachill

3
Điều này làm việc hoàn hảo cho tôi. đó thực sự là một quá trình 2 bước. 1. Thêm Bàn phímLayoutConstraint.swift, 2. Trong bảng phân cảnh, tạo một giới hạn dưới cùng cho dạng xem hoặc trường văn bản. LƯU Ý: Tôi đã xóa các ràng buộc của mình và chỉ thêm 1 ràng buộc vào dưới cùng của khung nhìn hoặc trường văn bản và thay đổi lớp của nó từ NSLayoutConstraint thành KeyboardLayoutConstraint. Sau đó, bất kỳ chế độ xem / trường văn bản, v.v. ở trên tôi chỉ kết nối các ràng buộc từ mục đó với mục đó bằng một Bàn phím duy nhấtLayoutConstraint và kết quả là tất cả các mục trong chế độ xem LÊN / XUỐNG khi Bàn phím xuất hiện / Biến mất
Brian

4
Đây là giải pháp tốt nhất, mã được cung cấp không mã hóa bất kỳ giá trị nào như chiều dài hoặc đường cong của hình ảnh động hoặc kích thước của bàn phím. Nó cũng dễ hiểu.
MiguelSantirso

3
Điều này đang làm việc với tôi, nhưng tôi có thêm 50px khoảng trống giữa đỉnh bàn phím và dưới cùng của scrollView. Tôi tự hỏi liệu có phải do hạn chế dưới cùng của Vùng an toàn mà tôi đang sử dụng không. Có ai chạy vào đây không?
Clifton Labrum

1
Đây là một câu trả lời tuyệt vời. Thiết kế rất mát mẻ là tốt. Một đề xuất: Nếu văn bản / trường văn bản của bạn nằm trên các ô xem bảng, bạn có thể nhận thấy các chế độ xem có ràng buộc này sẽ nhảy lúng túng mỗi khi người dùng nhấp vào và đi đến trường văn bản tiếp theo. Bạn có thể bọc hình ảnh động DispatchQueue.main.async {}để sửa nó. Làm tốt lắm! Đồng ý
ScottyBlades

68

Một trong những câu trả lời phổ biến về chủ đề này sử dụng đoạn mã sau:

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

Có một vấn đề rõ ràng với việc bù đắp tầm nhìn của bạn bằng một lượng tĩnh. Nó sẽ trông đẹp trên một thiết bị nhưng sẽ trông tệ trên mọi cấu hình kích thước khác. Bạn sẽ cần lấy chiều cao bàn phím và sử dụng giá trị đó làm giá trị bù của mình.

Đây là một giải pháp hoạt động trên tất cả các thiết bị và xử lý trường hợp cạnh trong đó người dùng ẩn trường văn bản dự đoán trong khi nhập.

Giải pháp

Điều quan trọng cần lưu ý dưới đây, chúng tôi sẽ chuyển self.view.window thành tham số đối tượng của chúng tôi. Điều này sẽ cung cấp cho chúng tôi dữ liệu từ Bàn phím của chúng tôi, chẳng hạn như chiều cao của nó!

@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
}

Chúng tôi sẽ làm cho nó trông đẹp hơn trên tất cả các thiết bị và xử lý trường hợp người dùng thêm hoặc xóa trường văn bản dự đoán.

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
        })
    }
}

Xóa quan sát

Đừng quên xóa người quan sát của bạn trước khi bạn rời khỏi chế độ xem để ngăn các tin nhắn không cần thiết được truyền đi.

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)
}

Cập nhật dựa trên câu hỏi từ ý kiến:

Nếu bạn có hai hoặc nhiều trường văn bản, bạn có thể kiểm tra xem view.frame.origin.y của bạn có bằng không.

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
khi xử lý nhiều trường văn bản, chế độ xem tiếp tục di chuyển lên và không quay xuống
Mugunthan Balakrishnan

Bạn sẽ phải thay đổi điều kiện của mình để giải thích cho các trường văn bản
Dan Beaulieu

cảm ơn vì đã trả lời, tôi đã tìm thấy câu trả lời mà tôi đang tìm kiếm trong chủ đề này về stack overflow stackoverflow.com/questions/1126726/ chủ
Mugunthan Balakrishnan

@MugunthanBalakrishnan cảm ơn vì đã đưa ra điều này, tôi đã thêm một giải pháp.
Dan Beaulieu

Chào các bạn, có một lỗi. Các quan sát viên không bị xóa khỏi chế độ xem sau khi được gọi trong viewWillDisappear. Thay thế dòng này "NSNotificationCenter.defaultCenter (). RemoveObserver (self, name: UIKeyboardWillHideNotification, object: self.view.window)" bằng "NSNotificationCenter.defaultCenter (). RemoveObserver (self, name:" đã bị xóa
rudald 20/03/18

29

Thêm phần này vào trình điều khiển khung nhìn của bạn. Hoạt động như một lá bùa. Chỉ cần điều chỉnh các giá trị.

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
}

Điều này làm việc cho tôi. Tuy nhiên nó là một chút giật. Làm thế nào tôi có thể có được điều này để di chuyển lên Smoothley? cũng có một cách để chỉ áp dụng nó cho một trong các trường văn bản như hiện tại nó làm điều này cho tất cả. :(
DannieCoderBoi

2
Nó có thể không hoạt động với "Tự động bố trí" vì vậy hãy xem xét tắt nó nếu có.
Teodor Ciuraru

1
Nó gây ra một số hành vi thú vị với autolayout @Josh, bạn đã nhầm
Mike

5
Đừng làm điều này! Bạn không thể cho rằng bàn phím có kích thước nhất định.
nielsbot

2
Nên sử dụng kích thước bàn phím. Điều gì xảy ra khi bạn có chế độ xem phụ kiện và chiều cao bàn phím khác nhau trên thiết bị? Bàn phím rời?
xtrinch

25

Tôi đã cải thiện một trong những câu trả lời một chút để làm cho nó hoạt động với các bàn phím khác nhau và các trường văn bản / trường khác nhau trên một trang:

Thêm người quan sát:

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
        }
    }
}

Xóa các quan sát viên:

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
giải pháp này hoạt động tốt hơn câu trả lời được chấp nhận. Câu trả lời được chấp nhận chỉ hiển thị bàn phím một lần mà với tôi là một lỗi :)
Masih

Điều này hoạt động cho Xcode 10.1 và iOS 12. Câu trả lời được chấp nhận không còn hiệu lực nữa.
zeeshan

Đây là một câu trả lời tuyệt vời, điều duy nhất tôi muốn thêm là theo dõi vùng an toàn dưới cùng trong các thiết bị mới hơn (X, XS, v.v.) để nó giải thích điều đó.
Munib

@Munib Xem stackoverflow.com/a/54993623/1485230 Các vấn đề khác bao gồm chế độ xem không hoạt hình và thay đổi chiều cao bàn phím không được theo dõi.
Antzi

Điều gì xảy ra nếu textField của tôi đứng đầu chế độ xem ..? ý tôi là nếu có trường văn bản có gốc Y = 0 .. ?? sau đó textField sẽ tăng lên và tôi không thể nhìn thấy nó
Saifan Nadaf

18

Không phải là một quảng cáo hoặc khuyến mãi hoặc thư rác , chỉ là một giải pháp tốt. Tôi biết rằng câu hỏi này có gần 30 câu trả lời và tôi rất sốc khi không ai nhắc đến một lần nào về dự án GitHub tuyệt đẹp này, tất cả đều dành cho bạn và thậm chí còn tốt hơn. Tất cả các câu trả lời chỉ cần di chuyển tầm nhìn lên trên. Tôi vừa giải quyết tất cả các vấn đề của mình với IQPalManager này. Nó có hơn 13000 ngôi sao.
Chỉ cần thêm phần này vào podfile của bạn nếu bạn đang sử dụng swift

pod 'IQKeyboardManagerSwift'

và sau đó bên trong AppDelegate.swift của bạn làm 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
    }
}

Thêm dòng IQKeyboardManager.shared.enable = trueđể kích hoạt nó
Giải pháp này là bắt buộc nếu bạn đang đi sản xuất.


Điều này thực sự tốt, nhưng phiên bản mới nhất không hoạt động với tôi, tôi đã sử dụng 6.2.1 và nhập import IQKeyboardManagervà sử dụng IQKeyboardManager.shared().isEnabled = truetrong AppDelegate
Dhanu K

2
Và điều này hoạt động khủng khiếp khi sử dụng nhiều văn bản chỉnh sửa, Điều này đã tiết kiệm thời gian của tôi
Dhanu K

1
Không thể cảm ơn đủ để chỉ ra thư viện tuyệt vời này. Thư viện này cuối cùng là TRẢ LỜI CUỐI CÙNG cho tất cả những điều vô nghĩa liên quan đến bàn phím mà Apple chưa bao giờ cung cấp giải pháp cho. Bây giờ tôi sẽ sử dụng nó cho tất cả các dự án của mình, mới và cũ, và tiết kiệm thời gian và đau đầu mà bàn phím này xuất hiện, biến mất hoặc không biến mất hoặc làm thế nào để ẩn nó và tại sao nó bị chồng chéo, các vấn đề đã gây ra cho tôi kể từ khi ngày tôi đang lập trình cho iPhone.
zeeshan

1
Tôi đã viết mã riêng của mình để di chuyển trường văn bản, giống như các giải pháp khác ở đây. Tôi thấy rằng IQPalManager rất tốt và tôi sẽ kết hợp nó từ bây giờ. Sẽ giữ cho mã của tôi tiện dụng chỉ trong trường hợp khung không được cập nhật.
TM Lynch

@DhanuK, Chỉ cần tìm thấy thư viện này và hoạt động hoàn hảo và thật dễ dàng. Mã đại biểu ứng dụng đã được cập nhật lên IQPalManager. Shared.enable = true
adougies

15

Đối với lỗi màn hình đen (Swift 4 & 4.2) .

Tôi đã khắc phục vấn đề màn hình đen. Trong giải pháp đã được xác minh Chiều cao bàn phím thay đổi sau khi chạm và điều này gây ra màn hình đen.

Phải sử dụng UIKeyboardFrameEndUserInfoKey thay vì UIKeyboardFrameBeginUserInfoKey

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
    }
}

Sẽ không hoạt động nếu có một thanh tab. Bạn phải tính chiều cao của thanh tab, nếu không sẽ có một khoảng cách màn hình đen giữa bàn phím và chế độ xem.
Ankur Lahiry

Điều này không khắc phục khu vực màu đen nơi bàn phím trên iPhone X và mới hơn. Và mỗi khi bàn phím xuất hiện và biến mất, khung nhìn chính tiếp tục trượt xuống.
Edison

14

Tôi thấy tất cả các câu trả lời đang tự di chuyển khung nhìn theo giá trị của chiều cao bàn phím. Vâng, tôi có một câu trả lời phức tạp, có thể hữu ích nếu bạn đang sử dụng các ràng buộc autolayout, nghĩa là di chuyển chế độ xem bằng cách thay đổi giá trị ràng buộc của nó (ví dụ ràng buộc dưới hoặc trên cùng) bằng một giá trị được xác định trước hoặc bạn có thể sử dụng giá trị kích thước bàn phím.

Trong ví dụ này, tôi sử dụng ràng buộc dưới cùng từ trường văn bản đến Chế độ xem bố cục dưới cùng với giá trị ban đầu là 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()
    }
}

Xin chào ông, ông có thể vui lòng cho tôi biết tại sao điều này không hoạt động khi được đặt trong chế độ xem cũng chứa TableView không? Nó hoạt động tốt trong cùng một kịch bản khi nó chứa CollectionView.
elarcoiris

9

Đã có một số thay đổi đối với cách chúng tôi xác định Bàn phímWillHideNotification.

Giải pháp này hoạt động với 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
Điều gì xảy ra nếu textField của tôi đứng đầu chế độ xem ..? ý tôi là nếu có trường văn bản có gốc Y = 0 .. ?? sau đó textField sẽ tăng lên và tôi không thể nhìn thấy nó
Saifan Nadaf

7

Swift 5.0:

Sau 4-5 giờ chiến đấu, tôi đã đến với một phần mở rộng đơn giản của UIViewControll với mã đơn giản hoạt động như bùa mê

* Chế độ xem không nên di chuyển khi TextField ở trên bàn phím

* Không cần đặt giá trị không đổi thành NSLayoutConstraint

* Không yêu cầu thư viện bên thứ ba

* Không yêu cầu mã hoạt hình

* Hoạt động trên viewview là tốt

* Điều này hoạt động trên Auto layout / auto resize

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
        }
    }
}

Thêm tiện ích mở rộng UIResponder này để chọn TextField nào được chọn

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
    }
}

Sau đó sử dụng cái này trong bất kỳ ViewContoder nào của bạn

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

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

  • Đăng ký thông báo này trong func viewWillAppear(_ animated: Bool)

  • Deregister Thông báo này trong func viewWillDisappear(_ animated:Bool)

    Tải về bản demo tại đây


Đây có vẻ là giải pháp tốt nhất, tuy nhiên có một vài lỗi. 1, trường văn bản di chuyển lên nhưng khi tôi bắt đầu gõ vào nó, nó nhảy lên một chút nữa. 2, Trong phong cảnh khi gõ textField đôi khi nhảy sang trái.
Darren

@Darren Tôi đang cố gắng tìm ra những lỗi này nhưng tôi không tìm thấy, bạn có thể vui lòng cho biết nơi bạn có những lỗi này không, ý tôi là cho phiên bản / thiết bị nào ... ??
Saifan Nadaf

6

Đối với Swift 3, tôi đã tạo một lớp con UIViewControll vì tôi cần hành vi không đổi trong tất cả các Bộ điều khiển xem.

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)
  }
}

Lấy cảm hứng từ giải pháp của Pavle, tôi đã nâng cấp nó để tự động nâng bàn phím theo một tỷ lệ phần trăm không gian còn lại nhất định và cũng tìm trường tập trung theo cách đệ quy để bố trí phù hợp. Lấy nó ở đây: gist.github.com/noordawod/24d32b2ce8363627ea73d7e5991009a0
Noor Dawod

Thanh tab của tôi cũng đang di chuyển lên với cửa sổ! :(
Alfi

6

Câu trả lời được xác thực không tính đến vị trí trường văn bản và có một số lỗi (dịch chuyển kép, không bao giờ quay lại vị trí chính, dịch chuyển ngay cả khi texfield ở trên cùng của chế độ xem ...)

Ý tưởng là:

  • để lấy trọng tâm TextField vị trí Y tuyệt đối
  • để có được chiều cao bàn phím
  • để có được màn hình
  • Sau đó tính khoảng cách giữa vị trí bàn phím và trường văn bản (nếu <0 -> di chuyển lên chế độ xem)
  • để sử dụng UIView.transform thay vì UIView.frame.origin.y - = .., khiến việc quay trở lại vị trí ban đầu với UIView.transform = .identity dễ dàng hơn

sau đó chúng ta sẽ chỉ có thể di chuyển chế độ xem nếu cần thiết và về sự dịch chuyển cụ thể trong oder để có texField tập trung ngay trên bàn phím

Đây là mã:

Swift 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
}

}


Rất tốt! (Trong viewDidLoad, bạn có "VehiculeViewContoder" thay vì chỉ "ViewContoder").
rene

Một câu trả lời đầy đủ và hữu ích hơn nhiều. Cảm ơn bạn! Tôi đề nghị kiểm tra bàn phím được gọi như sau vì nó sẽ cho kích thước phù hợp của bàn phím ......... nếu để bàn phímSize = (notify.userInfo? [UIResponder.keyboardFrameEndUserInfoKey] như? NSValue)?. CgRectValue .size
Ben

4

Tôi nhận thấy rằng các câu trả lời khác liên quan đến việc cắt một số đầu từ quan điểm. Nếu bạn chỉ muốn thay đổi kích thước khung nhìn mà không cắt bất kỳ nội dung nào, chỉ cần thử phương pháp này :)

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

Hai xu của tôi cho người mới bắt đầu: trong các mẫu ở trên có người thay đổi tọa độ, người khác sử dụng "mặt nạ tự động hóa" và các ràng buộc khác:

Như Apple nói, không trộn lẫn 3 loại logic này. Nếu bạn có các ràng buộc trong Storyboard, đừng cố thay đổi x / y. Nó chắc chắn không hoạt động.


4

Vì vậy, không có câu trả lời nào khác có vẻ đúng.

Bàn phím ứng xử tốt trên iOS nên:

  • Thay đổi kích thước tự động khi bàn phím thay đổi kích thước (CÓ THỂ CÓ THỂ)
  • Hoạt hình ở cùng tốc độ với bàn phím
  • Animate sử dụng cùng một đường cong như bàn phím
  • Tôn trọng các khu vực an toàn nếu có liên quan.
  • Hoạt động trên iPad / Chế độ không khóa

Mã của tôi sử dụng NSLayoutConstraintkhai báo là@IBOutlet

@IBOutlet private var bottomLayoutConstraint: NSLayoutConstraint!

Bạn cũng có thể sử dụng biến đổi, xem bù đắp, .... Tôi nghĩ rằng nó dễ dàng hơn với các ràng buộc tho. Nó hoạt động bằng cách đặt một ràng buộc xuống dưới cùng, bạn có thể cần phải thay đổi mã nếu hằng số của bạn không phải là 0 / Không phải ở dưới cùng.

Đây là mã:

// 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

Câu trả lời hoàn hảo 100% cho tất cả Chiều cao xem bàn của Guy khi mở Bàn phím

Dành cho Swift4.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
    }
}

Swift3.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
         }
    }

Đây là câu trả lời tốt nhất. tbl phải là bảngView và tôi đã thêm một số phần đệm: contentInset.bottom = keyboardFrame.size.height + 10
iphaaw

2

Dành cho Swift 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

Swift 4:

Tôi đã gặp vấn đề với câu trả lời được chấp nhận nhiều nhất, trong đó việc ẩn bàn phím không đưa chế độ xem hoàn toàn xuống cuối trang (chỉ một phần). Điều này làm việc cho tôi (+ cập nhật cho 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
        }
    }
}

Điều gì xảy ra nếu textField của tôi đứng đầu chế độ xem ..? ý tôi là nếu có trường văn bản có gốc Y = 0 .. ?? sau đó textField sẽ tăng lên và tôi không thể nhìn thấy nó
Saifan Nadaf

2

Tương tự như câu trả lời @Boris, nhưng trong 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

Đây là giải pháp của tôi (thực ra mã này dành cho trường hợp khi bạn có ít trường văn bản trong chế độ xem của mình, cách này cũng hoạt động cho trường hợp khi bạn có một trường văn bản)

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
        }
    }
}

Đừng quên đặt Đại biểu thành văn bản
Năng suất

Thay đổi điều kiện trong keyboardwillshow thành, nếu (! CGRectContainsPoint (aRect, newOrgin!) &&!
Self.viewWasMoved

thêm self.viewWasMoved = false khi bạn đặt lại khung
KingofBliss

1

Đã cập nhật cho Swift 3 ...

Như những người khác đã nói, bạn cần thêm trình quan sát thông báo trong phương thức viewDidLoad () của trình điều khiển, như vậy:

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()
    }

Hãy nhớ xóa người quan sát của bạn ở nơi thích hợp (tôi thực hiện theo phương thức 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)

Sau đó, triển khai các phương thức hiển thị và ẩn của bạn - chú ý dòng thông báo cho ứng dụng bỏ qua các sự kiện tương tác (BeginIgnoringInteractionEvents). Điều này rất quan trọng vì không có nó, người dùng có thể chạm vào một trường hoặc thậm chí là một cuộn xem và khiến sự thay đổi xảy ra lần thứ hai, dẫn đến một trục trặc giao diện người dùng khủng khiếp. Bỏ qua các sự kiện tương tác trước khi bàn phím hiển thị và ẩn sẽ ngăn điều này:

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
        }
    }

Cuối cùng, kích hoạt lại các tương tác của người dùng (hãy nhớ rằng phương thức này kích hoạt sau khi bàn phím didShow hoặc didHide):

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

1

Mã 3 Swift

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

Nếu bạn có 2 hoặc nhiều trường văn bản trên cùng một VC và người dùng chạm vào một trong số chúng và sau đó chạm vào một trường khác, mà không gọi chức năng bàn phímWillHide, thì chế độ xem sẽ tăng thêm một lần nữa, vì không cần thiết, bởi vì bạn sẽ có bàn phím, một khoảng trống có chiều cao của bàn phím và sau đó là chế độ xem, sử dụng mã trong câu trả lời tôi đã chỉnh sửa:

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
    }
}

Để giải quyết vấn đề này, hãy thay thế hai chức năng "KeyboardWillShow / Hide" thành các chức năng sau:

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
        }
    }
}

Điều gì xảy ra nếu textField của tôi đứng đầu chế độ xem ..? ý tôi là nếu có trường văn bản có gốc Y = 0 .. ?? sau đó textField sẽ tăng lên và tôi không thể nhìn thấy nó
Saifan Nadaf

1

Giải pháp của @ là RẤT tốt nhưng quan điểm đôi khi có thể bị hỏng.

Để căn chỉnh hoàn hảo, sử dụng mã dưới đây

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)}

Chức năng:

@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
    }
}}    

Và,

@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

video hướng dẫn này là tốt nhất. 7 phút dài và nó sẽ rất có ý nghĩa. Một giải pháp đơn giản như vậy khi bạn có nhiều trường văn bản và muốn chế độ xem cuộn di chuyển "x" lượng pixel khi trường văn bản cụ thể đó được gõ.

https://youtu.be/VuiPGJOEBH4

Chỉ cần các bước sau:

-Đặt tất cả các trường văn bản của bạn trong một cuộn xem bị giới hạn ở các cạnh của chế độ xem.

-Kết nối tất cả các trường văn bản và chế độ xem cuộn dưới dạng đại biểu cho trình điều khiển chế độ xem.

-Kết nối tất cả các trường văn bản và chế độ xem cuộn bằng IBOutlet.

class ViewController: UIViewController, UITextFieldDelegate {

-Thêm giao thức UITextFieldDelegate vào lớp của bạn

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

-Thêm các phương thức UITextFieldDelegate vào tệp swift của bạn:

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)
}

Phương pháp đầu tiên chỉ kích hoạt nút quay lại trên bàn phím để tắt bàn phím. Thứ hai là khi bạn chạm vào bất kỳ trường văn bản cụ thể nào, sau đó cài đặt độ lệch y của khoảng cách cuộn cuộn của bạn (khoảng cách của tôi dựa trên vị trí y trên bộ điều khiển chế độ xem của tôi 25,57,112,142). Điều cuối cùng nói khi bạn nhấn ra khỏi bàn phím, cuộn xem sẽ quay trở lại vị trí ban đầu.

Tôi đã làm cho pixel xem của tôi hoàn hảo theo cách này!


0

Tính năng shud này đã được xây dựng trong Ios, tuy nhiên chúng ta cần phải thực hiện bên ngoài.
Chèn mã bên dưới
* Để di chuyển chế độ xem khi textField nằm dưới bàn phím,
* Không di chuyển chế độ xem khi textField nằm trên bàn phím
* Để di chuyển Chế độ xem dựa trên chiều cao của bàn phím khi cần.
Điều này hoạt động và thử nghiệm trong mọi trường hợp.

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
    }
}

| :: | Đôi khi, Chế độ xem sẽ bị giảm, Trong trường hợp đó, hãy sử dụng chiều cao +/- 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
}

nó phải ổn định hơn


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

Sử dụng mã sau đây để xem Up trên UITextField Nhấp vào

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

Tôi đã tạo ra một cocoapod để đơn giản hóa vấn đề:

https://github.com/xtrinch/PalLayoutHelper

Làm thế nào để sử dụng nó:

Tạo một ràng buộc dưới cùng của bố cục tự động, cung cấp cho nó một lớp Bàn phímLayoutConstraint trong mô-đun Bàn phímLayoutHelper và nhóm sẽ thực hiện công việc cần thiết để tăng nó lên chỗ ở và xuất hiện bàn phím. Xem dự án ví dụ về các ví dụ về cách sử dụng nó (Tôi đã thực hiện hai: textField bên trong scrollView và textField được căn giữa theo chiều dọc với hai chế độ xem cơ bản - đăng nhập & đăng ký).

Ràng buộc bố cục dưới cùng có thể là của khung nhìn container, chính textField, bất cứ thứ gì, bạn đặt tên cho nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.