Przesuń pole tekstowe, gdy pojawi się klawiatura swift
Używam Swift do programowania z iOS i używam tego kodu, aby przenieść UITextField
, ale to nie działa. Wywołuję funkcję keyboardWillShow
poprawnie, ale pole tekstowe się nie rusza. Używam autolayout.
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);
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self);
}
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
//let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
var frame = self.ChatField.frame
frame.origin.y = frame.origin.y - keyboardSize.height + 167
self.chatField.frame = frame
println("asdasd")
}
}
30 answers
Istnieje kilka ulepszeń, które należy wprowadzić w istniejących odpowiedziach.
Po pierwsze UIKeyboardWillChangeFrameNotification jest prawdopodobnie najlepszym powiadomieniem, ponieważ obsługuje zmiany, które nie są tylko Pokaż/Ukryj, ale zmiany spowodowane zmianami klawiatury(język, korzystanie z klawiatur innych firm itp.) i rotacji.
Po Drugie parametry animacji można pobrać z powiadomienia, aby upewnić się, że animacje są prawidłowo połączone.
Są prawdopodobnie opcje czyszczenia up ten kod trochę bardziej, zwłaszcza jeśli są wygodne z siłą rozpakowywania kodu słownika.
Swift 3.x / 4.x
class MyViewController: UIViewController {
// This constraint ties an element at zero points from the bottom layout guide
@IBOutlet var keyboardHeightLayoutConstraint: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
// Note that SO highlighting makes the new selector syntax (#selector()) look
// like a comment but it isn't one
NotificationCenter.default.addObserver(self,
selector: #selector(self.keyboardNotification(notification:)),
name: NSNotification.Name.UIKeyboardWillChangeFrame,
object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func keyboardNotification(notification: NSNotification) {
if let userInfo = notification.userInfo {
let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
let endFrameY = endFrame.origin.y ?? 0
let duration:TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue
let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
if endFrameY >= UIScreen.main.bounds.size.height {
self.keyboardHeightLayoutConstraint?.constant = 0.0
} else {
self.keyboardHeightLayoutConstraint?.constant = endFrame?.size.height ?? 0.0
}
UIView.animate(withDuration: duration,
delay: TimeInterval(0),
options: animationCurve,
animations: { self.view.layoutIfNeeded() },
completion: nil)
}
}
Swift 2.x
class MyViewController: UIViewController {
// This constraint ties an element at zero points from the bottom layout guide
@IBOutlet var keyboardHeightLayoutConstraint: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
// Note that SO highlighting makes the new selector syntax (#selector()) look
// like a comment but it isn't one
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(self.keyboardNotification(_:)),
name: UIKeyboardWillChangeFrameNotification,
object: nil)
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func keyboardNotification(notification: NSNotification) {
if let userInfo = notification.userInfo {
let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
let duration:NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseInOut.rawValue
let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
if endFrame?.origin.y >= UIScreen.mainScreen().bounds.size.height {
self.keyboardHeightLayoutConstraint?.constant = 0.0
} else {
self.keyboardHeightLayoutConstraint?.constant = endFrame?.size.height ?? 0.0
}
UIView.animateWithDuration(duration,
delay: NSTimeInterval(0),
options: animationCurve,
animations: { self.view.layoutIfNeeded() },
completion: nil)
}
}
(edytowane w celu uwzględnienia animacji klawiatury poza ekranem zamiast kurczenia się, zgodnie z niesamowitym komentarzem @ Gabox poniżej)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-19 12:18:17
Jeśli używasz układu Auto, zakładam, że ustawiłeś spację dolną na ograniczenie Superview. W takim przypadku wystarczy zaktualizować wartość ograniczenia. Oto jak to zrobić z odrobiną animacji.
func keyboardWasShown(notification: NSNotification) {
let info = notification.userInfo!
let keyboardFrame: CGRect = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
UIView.animateWithDuration(0.1, animations: { () -> Void in
self.bottomConstraint.constant = keyboardFrame.size.height + 20
})
}
Hardcoded 20 jest dodawany tylko po to, aby pop pole tekstowe nad klawiaturą tylko trochę. W przeciwnym razie górny margines klawiatury i dolny margines textfield byłyby dotykające.
Gdy klawiatura zostanie odrzucona, zresetuj wartość ograniczenia do jego oryginalny.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-09 08:01:22
Prostym rozwiązaniem jest przesunięcie widoku w górę ze stałą wysokością klawiatury.
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(sender: NSNotification) {
self.view.frame.origin.y = -150 // Move view 150 points upward
}
func keyboardWillHide(sender: NSNotification) {
self.view.frame.origin.y = 0 // Move view to original position
}
Swift 3
NotificationCenter.default.addObserver(self, selector: #selector(RegisterViewController.keyboardWillShow(sender:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(RegisterViewController.keyboardWillHide(sender:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-02 07:33:39
Do przesuwania widoku podczas edycji textfield spróbuj tego, zastosowałem to, działa dobrze
func textFieldDidBeginEditing(textField: UITextField) {
self.animateViewMoving(up: true, moveValue: 100)
}
func textFieldDidEndEditing(textField: UITextField) {
self.animateViewMoving(up: false, moveValue: 100)
}
func animateViewMoving (up:Bool, moveValue :CGFloat){
var movementDuration:NSTimeInterval = 0.3
var movement:CGFloat = ( up ? -moveValue : moveValue)
UIView.beginAnimations( "animateView", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration )
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
UIView.commitAnimations()
}
Otrzymałem odpowiedź z tego źródła UITextField przesuń w górę, gdy klawiatura pojawi się w Swift
W Swift 4 - - -
func textFieldDidBeginEditing(_ textField: UITextField) {
animateViewMoving(up: true, moveValue: 100)
}
func textFieldDidEndEditing(_ textField: UITextField) {
animateViewMoving(up: false, moveValue: 100)
}
func animateViewMoving (up:Bool, moveValue :CGFloat){
let movementDuration:TimeInterval = 0.3
let movement:CGFloat = ( up ? -moveValue : moveValue)
UIView.beginAnimations( "animateView", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration )
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
UIView.commitAnimations()
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-08 04:59:19
Uwielbiam czysty kod Swift. Oto najciaśniejszy kod, jaki mogłem wymyślić, aby przesunąć widok tekstu w górę / w dół za pomocą klawiatury. Obecnie działa w aplikacji produkcyjnej iOS8 / 9 Swift 2.
Aktualizacja (Marzec 2016): Właśnie zaostrzyłem mój poprzedni kod tak bardzo, jak to możliwe. Ponadto, istnieje kilka popularnych odpowiedzi tutaj, które hardcode wysokość klawiatury i parametry animacji. Nie ma takiej potrzeby, nie wspominając o tym, że liczby w tych odpowiedziach nie zawsze zgadzają się z rzeczywistymi wartości widzę na moim 6s+ iOS9(wysokość klawiatury 226, czas trwania 0.25 i Krzywa animacji 7). W każdym razie prawie nie ma dodatkowego kodu, aby uzyskać te wartości prosto z systemu. Patrz poniżej.
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "animateWithKeyboard:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "animateWithKeyboard:", name: UIKeyboardWillHideNotification, object: nil)
}
func animateWithKeyboard(notification: NSNotification) {
// Based on both Apple's docs and personal experience,
// I assume userInfo and its documented keys are available.
// If you'd like, you can remove the forced unwrapping and add your own default values.
let userInfo = notification.userInfo!
let keyboardHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt
let moveUp = (notification.name == UIKeyboardWillShowNotification)
// baseContraint is your Auto Layout constraint that pins the
// text view to the bottom of the superview.
baseConstraint.constant = moveUp ? -keyboardHeight : 0
let options = UIViewAnimationOptions(rawValue: curve << 16)
UIView.animateWithDuration(duration, delay: 0, options: options,
animations: {
self.view.layoutIfNeeded()
},
completion: nil
)
}
Uwaga: Ten kod obejmuje najbardziej komentowany / ogólny przypadek. Jednak, więcej kodu może być potrzebne do obsługi różnych orientacji i/lub niestandardowych klawiatur Oto dogłębny artykuł na temat pracy z klawiaturą iOS. Jeśli musisz obsłużyć każdy scenariusz, może to pomóc.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-03 17:23:26
Edit : polecam łatwiejsze i czystsze rozwiązanie. Po prostu zmień klasę ograniczenia dolnego odstępu na KeyboardLayoutConstraint. Automatycznie rozszerzy się na wysokość klawiatury.
To jest ulepszona wersja odpowiedzi @ JosephLord. [7]} jak testowany na iOS 8.3 iPad Simulator, Portret. Xcode6. 3 beta4, znalazłem jego odpowiedź nie działa, gdy klawiatura się ukrywa, ponieważ
UIKeyboardFrameEndUserInfoKey
jest "NSRect: {{0, 1024}, {768, 264}}";
. Wysokość nigdy nie jest 0
.
To wraca do użyj tradycyjnych UIKeyboardWillShowNotification
i UIKeyboardWillHideNotification
, aby lepiej określić, kiedy klawiatura jest ukryta, zamiast polegać na wysokości ramki końcowej. UIKeyboardWillShowNotification
jest również wysyłany po zmianie ramki klawiatury, więc powinien obejmować wszystkie przypadki użycia.
// You have to set this up in storyboard first!.
// It's a vertical spacing constraint between view and bottom of superview.
@IBOutlet weak var bottomSpacingConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardNotification:"), name:UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardNotification:"), name:UIKeyboardWillHideNotification, object: nil);
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func keyboardNotification(notification: NSNotification) {
let isShowing = notification.name == UIKeyboardWillShowNotification
if let userInfo = notification.userInfo {
let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
let endFrameHeight = endFrame?.size.height ?? 0.0
let duration:NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseInOut.rawValue
let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
self.bottomSpacingConstraint?.constant = isShowing ? endFrameHeight : 0.0
UIView.animateWithDuration(duration,
delay: NSTimeInterval(0),
options: animationCurve,
animations: { self.view.layoutIfNeeded() },
completion: nil)
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-03 05:59:53
Jest to ulepszona wersja odpowiedzi @ JosephLord i @ Hlung. Może mieć zastosowanie niezależnie od tego, czy masz pasek Tabb, czy nie. I doskonale przywróci widok, który jest przesuwany przez klawiaturę do pierwotnej pozycji.
// You have to set this up in storyboard first!.
// It's a vertical spacing constraint between view and bottom of superview.
@IBOutlet weak var bottomSpacingConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// Receive(Get) Notification
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardNotification:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardNotification:", name: UIKeyboardWillHideNotification, object: nil)
self.originalConstraint = self.keyboardHeightLayoutConstraint?.constant //for original coordinate.
}
func keyboardNotification(notification: NSNotification) {
let isShowing = notification.name == UIKeyboardWillShowNotification
var tabbarHeight: CGFloat = 0
if self.tabBarController? != nil {
tabbarHeight = self.tabBarController!.tabBar.frame.height
}
if let userInfo = notification.userInfo {
let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
let duration:NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseInOut.rawValue
let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
self.keyboardHeightLayoutConstraint?.constant = isShowing ? (endFrame!.size.height - tabbarHeight) : self.originalConstraint!
UIView.animateWithDuration(duration,
delay: NSTimeInterval(0),
options: animationCurve,
animations: { self.view.layoutIfNeeded() },
completion: nil)
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-28 05:51:55
Najprostszy sposób, który nie wymaga żadnego kodu:
- Pobierz KeyboardLayoutConstraint.swift i dodaj (przeciągnij i upuść) plik do projektu, jeśli nie używasz jeszcze Spring animation framework.
- w scenariuszu Utwórz dolne ograniczenie dla obiektu / widoku / pola tekstowego, wybierz ograniczenie (kliknij je dwukrotnie) i w Inspektorze tożsamości zmień jego klasę z NSLayoutConstraint na KeyboardLayoutConstraint. Zrobione!
The obiekt automatycznie przesunie się w górę za pomocą klawiatury, zsynchronizowanej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-17 21:30:54
Stworzyłem protokół Swift 3 do obsługi wyglądu / znikania klawiatury
import UIKit
protocol KeyboardHandler: class {
var bottomConstraint: NSLayoutConstraint! { get set }
func keyboardWillShow(_ notification: Notification)
func keyboardWillHide(_ notification: Notification)
func startObservingKeyboardChanges()
func stopObservingKeyboardChanges()
}
extension KeyboardHandler where Self: UIViewController {
func startObservingKeyboardChanges() {
// NotificationCenter observers
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillShow, object: nil, queue: nil) { [weak self] notification in
self?.keyboardWillShow(notification)
}
// Deal with rotations
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil, queue: nil) { [weak self] notification in
self?.keyboardWillShow(notification)
}
// Deal with keyboard change (emoji, numerical, etc.)
NotificationCenter.default.addObserver(forName: NSNotification.Name.UITextInputCurrentInputModeDidChange, object: nil, queue: nil) { [weak self] notification in
self?.keyboardWillShow(notification)
}
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillHide, object: nil, queue: nil) { [weak self] notification in
self?.keyboardWillHide(notification)
}
}
func keyboardWillShow(_ notification: Notification) {
let verticalPadding: CGFloat = 20 // Padding between the bottom of the view and the top of the keyboard
guard let value = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else { return }
let keyboardHeight = value.cgRectValue.height
// Here you could have more complex rules, like checking if the textField currently selected is actually covered by the keyboard, but that's out of this scope.
self.bottomConstraint.constant = keyboardHeight + verticalPadding
UIView.animate(withDuration: 0.1, animations: { () -> Void in
self.view.layoutIfNeeded()
})
}
func keyboardWillHide(_ notification: Notification) {
self.bottomConstraint.constant = 0
UIView.animate(withDuration: 0.1, animations: { () -> Void in
self.view.layoutIfNeeded()
})
}
func stopObservingKeyboardChanges() {
NotificationCenter.default.removeObserver(self)
}
}
Następnie, aby zaimplementować go w UIViewController, wykonaj następujące czynności:
-
Niech viewController będzie zgodny z tym protokołem:
class FormMailVC: UIViewControlle, KeyboardHandler {
-
Zacznij obserwować zmiany klawiatury w viewWillAppear:
// MARK: - View controller life cycle override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) startObservingKeyboardChanges() }
-
Przestań obserwować zmiany klawiatury w viewWillDisappear:
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) stopObservingKeyboardChanges() }
-
Utwórz IBOutlet dla dolnego ograniczenia z storyboard:
// NSLayoutConstraints @IBOutlet weak var bottomConstraint: NSLayoutConstraint!
(polecam mieć cały interfejs użytkownika osadzony wewnątrz "contentView" i powiązanie z tą właściwością dolnego ograniczenia z tego contentView do dolnego przewodnika po Układzie)
-
Zmiana priorytetu ograniczenia górnego ograniczenia na 250 (niski)
Ma to na celu przesunięcie całej zawartości w górę, gdy pojawi się klawiatura. Priorytet musi być niższy niż jakikolwiek inny priorytet ograniczenia w podglądzie, w tym priorytety Przytulania treści / priorytety odporności na kompresję treści.
- Upewnij się, że funkcja Autolayout ma wystarczająco dużo ograniczeń, aby określić, w jaki sposób Widok contentView powinien się przesuwać.
Być może będziesz musiał dodać ograniczenie "większe niż równe" dla tego:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-18 11:03:44
Takie proste UIViewController
rozszerzenie może być używane
//MARK: - Observers
extension UIViewController {
func addObserverForNotification(notificationName: String, actionBlock: (NSNotification) -> Void) {
NSNotificationCenter.defaultCenter().addObserverForName(notificationName, object: nil, queue: NSOperationQueue.mainQueue(), usingBlock: actionBlock)
}
func removeObserver(observer: AnyObject, notificationName: String) {
NSNotificationCenter.defaultCenter().removeObserver(observer, name: notificationName, object: nil)
}
}
//MARK: - Keyboard observers
extension UIViewController {
typealias KeyboardHeightClosure = (CGFloat) -> ()
func addKeyboardChangeFrameObserver(willShow willShowClosure: KeyboardHeightClosure?,
willHide willHideClosure: KeyboardHeightClosure?) {
NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardWillChangeFrameNotification,
object: nil, queue: NSOperationQueue.mainQueue(), usingBlock: { [weak self](notification) in
if let userInfo = notification.userInfo,
let frame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue(),
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double,
let c = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt,
let kFrame = self?.view.convertRect(frame, fromView: nil),
let kBounds = self?.view.bounds {
let animationType = UIViewAnimationOptions(rawValue: c)
let kHeight = kFrame.size.height
UIView.animateWithDuration(duration, delay: 0, options: animationType, animations: {
if CGRectIntersectsRect(kBounds, kFrame) { // keyboard will be shown
willShowClosure?(kHeight)
} else { // keyboard will be hidden
willHideClosure?(kHeight)
}
}, completion: nil)
} else {
print("Invalid conditions for UIKeyboardWillChangeFrameNotification")
}
})
}
func removeKeyboardObserver() {
removeObserver(self, notificationName: UIKeyboardWillChangeFrameNotification)
}
}
Przykład użycia
override func viewWillDisappear(animated: Bool) {
super.viewDidDisappear(animated)
removeKeyboardObserver()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
addKeyboardChangeFrameObserver(willShow: { [weak self](height) in
//Update constraints here
self?.view.setNeedsUpdateConstraints()
}, willHide: { [weak self](height) in
//Reset constraints here
self?.view.setNeedsUpdateConstraints()
})
}
Swift 4 solution
//MARK: - Observers
extension UIViewController {
func addObserverForNotification(_ notificationName: Notification.Name, actionBlock: @escaping (Notification) -> Void) {
NotificationCenter.default.addObserver(forName: notificationName, object: nil, queue: OperationQueue.main, using: actionBlock)
}
func removeObserver(_ observer: AnyObject, notificationName: Notification.Name) {
NotificationCenter.default.removeObserver(observer, name: notificationName, object: nil)
}
}
//MARK: - Keyboard handling
extension UIViewController {
typealias KeyboardHeightClosure = (CGFloat) -> ()
func addKeyboardChangeFrameObserver(willShow willShowClosure: KeyboardHeightClosure?,
willHide willHideClosure: KeyboardHeightClosure?) {
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillChangeFrame,
object: nil, queue: OperationQueue.main, using: { [weak self](notification) in
if let userInfo = notification.userInfo,
let frame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double,
let c = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt,
let kFrame = self?.view.convert(frame, from: nil),
let kBounds = self?.view.bounds {
let animationType = UIViewAnimationOptions(rawValue: c)
let kHeight = kFrame.size.height
UIView.animate(withDuration: duration, delay: 0, options: animationType, animations: {
if kBounds.intersects(kFrame) { // keyboard will be shown
willShowClosure?(kHeight)
} else { // keyboard will be hidden
willHideClosure?(kHeight)
}
}, completion: nil)
} else {
print("Invalid conditions for UIKeyboardWillChangeFrameNotification")
}
})
}
func removeKeyboardObserver() {
removeObserver(self, notificationName: NSNotification.Name.UIKeyboardWillChangeFrame)
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-12 11:28:11
struct MoveKeyboard {
static let KEYBOARD_ANIMATION_DURATION : CGFloat = 0.3
static let MINIMUM_SCROLL_FRACTION : CGFloat = 0.2;
static let MAXIMUM_SCROLL_FRACTION : CGFloat = 0.8;
static let PORTRAIT_KEYBOARD_HEIGHT : CGFloat = 216;
static let LANDSCAPE_KEYBOARD_HEIGHT : CGFloat = 162;
}
func textFieldDidBeginEditing(textField: UITextField) {
let textFieldRect : CGRect = self.view.window!.convertRect(textField.bounds, fromView: textField)
let viewRect : CGRect = self.view.window!.convertRect(self.view.bounds, fromView: self.view)
let midline : CGFloat = textFieldRect.origin.y + 0.5 * textFieldRect.size.height
let numerator : CGFloat = midline - viewRect.origin.y - MoveKeyboard.MINIMUM_SCROLL_FRACTION * viewRect.size.height
let denominator : CGFloat = (MoveKeyboard.MAXIMUM_SCROLL_FRACTION - MoveKeyboard.MINIMUM_SCROLL_FRACTION) * viewRect.size.height
var heightFraction : CGFloat = numerator / denominator
if heightFraction < 0.0 {
heightFraction = 0.0
} else if heightFraction > 1.0 {
heightFraction = 1.0
}
let orientation : UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation
if (orientation == UIInterfaceOrientation.Portrait || orientation == UIInterfaceOrientation.PortraitUpsideDown) {
animateDistance = floor(MoveKeyboard.PORTRAIT_KEYBOARD_HEIGHT * heightFraction)
} else {
animateDistance = floor(MoveKeyboard.LANDSCAPE_KEYBOARD_HEIGHT * heightFraction)
}
var viewFrame : CGRect = self.view.frame
viewFrame.origin.y -= animateDistance
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(NSTimeInterval(MoveKeyboard.KEYBOARD_ANIMATION_DURATION))
self.view.frame = viewFrame
UIView.commitAnimations()
}
func textFieldDidEndEditing(textField: UITextField) {
var viewFrame : CGRect = self.view.frame
viewFrame.origin.y += animateDistance
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(NSTimeInterval(MoveKeyboard.KEYBOARD_ANIMATION_DURATION))
self.view.frame = viewFrame
UIView.commitAnimations()
}
I wreszcie, ponieważ używamy metod delegatów
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
Refaktored from using objective-c http://www.cocoawithlove.com/2008/10/sliding-uitextfields-around-to-avoid.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-12 10:07:23
Inne rozwiązanie, które nie zależy od autolayout, ograniczeń lub jakichkolwiek gniazd. Potrzebne są pola w widoku przewijania.
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "makeSpaceForKeyboard:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "makeSpaceForKeyboard:", name: UIKeyboardWillHideNotification, object: nil)
}
func makeSpaceForKeyboard(notification: NSNotification) {
let info = notification.userInfo!
let keyboardHeight:CGFloat = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().size.height
let duration:Double = info[UIKeyboardAnimationDurationUserInfoKey] as! Double
if notification.name == UIKeyboardWillShowNotification {
UIView.animateWithDuration(duration, animations: { () -> Void in
var frame = self.view.frame
frame.size.height = frame.size.height - keyboardHeight
self.view.frame = frame
})
} else {
UIView.animateWithDuration(duration, animations: { () -> Void in
var frame = self.view.frame
frame.size.height = frame.size.height + keyboardHeight
self.view.frame = frame
})
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-24 14:06:25
Oto moja wersja rozwiązania dla Swift 2.2:
Pierwsza rejestracja dla powiadomień Pokaż/ukryj klawiaturę
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(MessageThreadVC.keyboardWillShow(_:)),
name: UIKeyboardWillShowNotification,
object: nil)
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(MessageThreadVC.keyboardWillHide(_:)),
name: UIKeyboardWillHideNotification,
object: nil)
Następnie w methods coresponding dla tych powiadomień przesuń główny widok w górę lub w dół
func keyboardWillShow(sender: NSNotification) {
if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
self.view.frame.origin.y = -keyboardSize.height
}
}
func keyboardWillHide(sender: NSNotification) {
self.view.frame.origin.y = 0
}
Sztuczka jest w części "keyboardWillShow", która pobiera połączenia za każdym razem, gdy" QuickType Suggestion Bar " jest rozwijany lub zwinięty. Wtedy zawsze ustawiamy współrzędną Y głównego widoku, która jest równa ujemnej wartości całkowitej wysokości klawiatury (z lub bez Część" QuickType bar").
Na końcu nie zapomnij usunąć obserwatorów
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-12 13:33:51
Poniżej przedstawiono proste rozwiązanie, w którym pole tekstowe ma ograniczenie związane z dolnym przewodnikiem układu. Po prostu dodaje wysokość klawiatury do stałej ograniczenia.
// This constraint ties the text field to the bottom layout guide
@IBOutlet var textFieldToBottomLayoutGuideConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name:UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name:UIKeyboardWillHideNotification, object: nil);
}
func keyboardWillShow(sender: NSNotification) {
if let keyboardSize = (sender.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.textFieldToBottomLayoutGuideConstraint?.constant += keyboardSize.height
}
}
func keyboardWillHide(sender: NSNotification) {
if let keyboardSize = (sender.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.textFieldToBottomLayoutGuideConstraint?.constant -= keyboardSize.height
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-23 11:03:44
Cóż, myślę, że może być za późno, ale znalazłem inną prostą wersję odpowiedzi Saqiba. Używam Autolayout z ograniczeniami. Mam mały widok wewnątrz innego widoku głównego z polami nazwy użytkownika i hasła. Zamiast zmieniać współrzędną y widoku zapisuję oryginalną wartość ograniczenia w zmiennej i zmieniam stałą ograniczenia na jakąś wartość i ponownie po odrzuceniu klawiatury, konfiguruję ograniczenie na oryginalną. W ten sposób unika się problemu Odpowiedź Saqib ma, (widok utrzymuje się w górę i nie zatrzymuje się). Poniżej znajduje się mój kod...
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);
self.originalConstraint = self.centerYConstraint.constant
}
func keyboardWillShow(sender: NSNotification) {
self.centerYConstraint.constant += 30
}
func keyboardWillHide(sender: NSNotification) {
self.centerYConstraint.constant = self.originalConstraint
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-15 21:16:52
Możesz użyć tej biblioteki i tylko jeden wiersz kodu w appDidFinishedLaunching i u są gotowe..
func application(application: UIApplication,didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
IQKeyboardManager.sharedManager().enable = true
return true
}
IQKeyboardManager-Dostosuj widok za każdym razem, gdy pojawi się klawiatura link - https://github.com/hackiftekhar/IQKeyboardManager
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-16 06:17:41
Pracuję z swift 4 i rozwiązałem ten problem bez użycia dodatkowego ograniczenia dolnego spójrz mój kod jest tutaj.its really working on my case
1) Add Notification Observer in did load
override func viewDidLoad() { super.viewDidLoad() setupManager() // Do any additional setup after loading the view. 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) }
2) Usuń Notification Observer jak
deinit { NotificationCenter.default.removeObserver(self) }
3) Dodaj klawiaturę Pokaż / Ukryj metody jak
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
UIView.animate(withDuration: 0.1, animations: { () -> Void in
self.view.frame.origin.y -= keyboardSize.height
self.view.layoutIfNeeded()
})
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
UIView.animate(withDuration: 0.1, animations: { () -> Void in
self.view.frame.origin.y += keyboardSize.height
self.view.layoutIfNeeded()
})
}
}
4) Add textfeild delegate and add touchesBegan methods .przydatny do ukrycia klawiatury, gdy dotknij poza tekstem na ekranie
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-30 12:01:30
Użyłem tego samouczka, aby przesunąć pole tekstowe nad klawiaturą. Kod jest czysty i nie jest błędny.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-03 20:05:55
Zrobiłem w następujący sposób:
Jest to przydatne, gdy textfield superview jest view
class AdminLoginViewController: UIViewController,
UITextFieldDelegate{
@IBOutlet weak var txtUserName: UITextField!
@IBOutlet weak var txtUserPassword: UITextField!
@IBOutlet weak var btnAdminLogin: UIButton!
private var activeField : UIView?
var param:String!
var adminUser : Admin? = nil
var kbHeight: CGFloat!
override func viewDidLoad()
{
self.addKeyBoardObserver()
self.addGestureForHideKeyBoard()
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func addGestureForHideKeyBoard()
{
let tapGesture = UITapGestureRecognizer(target: self, action: Selector("hideKeyboard"))
tapGesture.cancelsTouchesInView = false
view.addGestureRecognizer(tapGesture)
}
func hideKeyboard() {
self.view.endEditing(true)
}
func addKeyBoardObserver(){
NSNotificationCenter.defaultCenter().addObserver(self, selector: "willChangeKeyboardFrame:",
name:UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "willChangeKeyboardFrame:",
name:UIKeyboardWillHideNotification, object: nil)
}
func removeObserver(){
NSNotificationCenter.defaultCenter().removeObserver(self)
}
//MARK:- textfiled Delegate
func textFieldShouldBeginEditing(textField: UITextField) -> Bool
{
activeField = textField
return true
}
func textFieldShouldEndEditing(textField: UITextField) -> Bool
{
if activeField == textField
{
activeField = nil
}
return true
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
if txtUserName == textField
{
txtUserPassword.becomeFirstResponder()
}
else if (textField == txtUserPassword)
{
self.btnAdminLoginAction(nil)
}
return true;
}
func willChangeKeyboardFrame(aNotification : NSNotification)
{
if self.activeField != nil && self.activeField!.isFirstResponder()
{
if let keyboardSize = (aNotification.userInfo![UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
{
let dy = (self.activeField?.superview?.convertRect((self.activeField?.frame)!, toView: view).origin.y)!
let height = (self.view.frame.size.height - keyboardSize.size.height)
if dy > height
{
var frame = self.view.frame
frame.origin.y = -((dy - height) + (self.activeField?.frame.size.height)! + 20)
self.view.frame = frame
}
}
}
else
{
var frame = self.view.frame
frame.origin.y = 0
self.view.frame = frame
}
} }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-16 06:00:22
func registerForKeyboardNotifications()
{
//Keyboard
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWasShown), name: UIKeyboardDidShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillBeHidden), name: UIKeyboardDidHideNotification, object: nil)
}
func deregisterFromKeyboardNotifications(){
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWasShown(notification: NSNotification){
let userInfo: NSDictionary = notification.userInfo!
let keyboardInfoFrame = userInfo.objectForKey(UIKeyboardFrameEndUserInfoKey)?.CGRectValue()
let windowFrame:CGRect = (UIApplication.sharedApplication().keyWindow!.convertRect(self.view.frame, fromView:self.view))
let keyboardFrame = CGRectIntersection(windowFrame, keyboardInfoFrame!)
let coveredFrame = UIApplication.sharedApplication().keyWindow!.convertRect(keyboardFrame, toView:self.view)
let contentInsets = UIEdgeInsetsMake(0, 0, (coveredFrame.size.height), 0.0)
self.scrollViewInAddCase .contentInset = contentInsets;
self.scrollViewInAddCase.scrollIndicatorInsets = contentInsets;
self.scrollViewInAddCase.contentSize = CGSizeMake((self.scrollViewInAddCase.contentSize.width), (self.scrollViewInAddCase.contentSize.height))
}
/**
this method will fire when keyboard was hidden
- parameter notification: contains keyboard details
*/
func keyboardWillBeHidden (notification: NSNotification) {
self.scrollViewInAddCase.contentInset = UIEdgeInsetsZero
self.scrollViewInAddCase.scrollIndicatorInsets = UIEdgeInsetsZero
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-16 13:02:57
Zrobiłem w następujący sposób:
class SignInController: UIViewController , UITextFieldDelegate {
@IBOutlet weak var scrollView: UIScrollView!
// outlet declartion
@IBOutlet weak var signInTextView: UITextField!
var kbHeight: CGFloat!
/**
*
* @method viewDidLoad
*
*/
override func viewDidLoad() {
super.viewDidLoad()
self.signInTextView.delegate = self
}// end viewDidLoad
/**
*
* @method viewWillAppear
*
*/
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
}// end viewWillAppear
/**
*
* @method viewDidAppear
*
*/
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}// end viewDidAppear
/**
*
* @method viewWillDisappear
*
*/
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self)
}
/**
*
* @method textFieldShouldReturn
* retun the keyboard value
*
*/
// MARK -
func textFieldShouldReturn(textField: UITextField) -> Bool {
signInTextView.resignFirstResponder()
return true;
}// end textFieldShouldReturn
// MARK - keyboardWillShow
func keyboardWillShow(notification: NSNotification) {
if let userInfo = notification.userInfo {
if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
kbHeight = keyboardSize.height
self.animateTextField(true)
}
}
}// end keyboardWillShow
// MARK - keyboardWillHide
func keyboardWillHide(notification: NSNotification) {
self.animateTextField(false)
}// end keyboardWillHide
// MARK - animateTextField
func animateTextField(up: Bool) {
var movement = (up ? -kbHeight : kbHeight)
UIView.animateWithDuration(0.3, animations: {
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
})
}// end animateTextField
/**
*
* @method didReceiveMemoryWarning
*
*/
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}// end didReceiveMemoryWarning
}// end SignInController
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-08 11:56:19
Jeśli jesteś taki jak ja, który wypróbował wszystkie powyższe rozwiązania i nadal twój problem nie jest rozwiązany, mam dla Ciebie świetne rozwiązanie, które działa jak urok. Najpierw chcę wyjaśnić kilka rzeczy na temat niektórych rozwiązań wymienionych powyżej.
- w moim przypadku IQkeyboardmanager działał tylko wtedy, gdy nie zastosowano automatycznego układu na elementach, jeśli zostanie zastosowany, to iqkeyboard manager nie będzie działał tak, jak myślimy.
- to samo z ruchem w górę siebie.widok.
- mam wriiten nagłówek objective c z szybkim wsparciem dla przesuwania UITexfield w górę, gdy użytkownik kliknie na niego, rozwiązując problem klawiatury pokrywającej UITextfield : https://github.com/coolvasanth/smart_keyboard . [3]}osoba, która ma średni lub wyższy poziom w tworzeniu aplikacji na iOS, może łatwo zrozumieć repozytorium i wdrożyć je. Wszystkiego najlepszego
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-08 11:28:21
Zmodyfikowałem trochę rozwiązanie @ Simpa.........
override func viewDidLoad()
{
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("makeSpaceForKeyboard:"), name:UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("makeSpaceForKeyboard:"), name:UIKeyboardWillHideNotification, object: nil);
}
deinit{
NSNotificationCenter.defaultCenter().removeObserver(self)
}
var keyboardIsVisible = false
override func makeSpaceForKeyboard(notification: NSNotification) {
let info = notification.userInfo!
let keyboardHeight:CGFloat = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().size.height
let duration:Double = info[UIKeyboardAnimationDurationUserInfoKey] as! Double
if notification.name == UIKeyboardWillShowNotification && keyboardIsVisible == false{
keyboardIsVisible = true
UIView.animateWithDuration(duration, animations: { () -> Void in
var frame = self.view.frame
frame.size.height = frame.size.height - keyboardHeight
self.view.frame = frame
})
} else if keyboardIsVisible == true && notification.name == UIKeyboardWillShowNotification{
}else {
keyboardIsVisible = false
UIView.animateWithDuration(duration, animations: { () -> Void in
var frame = self.view.frame
frame.size.height = frame.size.height + keyboardHeight
self.view.frame = frame
})
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-13 09:05:02
Żaden z nich nie działał i skończyło się na użyciu wstawek zawartości, aby przenieść mój widok w górę, gdy pojawi się klawiatura.
Uwaga: używałem UITableView
Referred solution @ keyboard-content-offset który został w całości napisany w objective C, poniższym rozwiązaniem jest clean Swift.
Dodaj notification observer @ viewDidLoad ()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(yourClass.keyboardWillBeShown), name:UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(yourClass.keyboardWillBeHidden), name:UIKeyboardWillHideNotification, object: nil);
Aby uzyskać rozmiar klawiatury, najpierw otrzymujemy słownik userInfo z obiektu notification, który przechowuje wszelkie dodatkowe obiekty, z których może korzystać nasz odbiornik.
Z tego słownika możemy uzyskać obiekt cgrect opisujący ramkę klawiatury za pomocą klawisza UIKeyboardFrameBeginUserInfoKey.
Zastosuj wstawkę zawartości dla metody table view @ keyboardWillBeShown,
func keyboardWillBeShown(sender: NSNotification)
{
// Move the table view
if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
{
let contentInsets = UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.height), 0.0);
yourTableView.contentInset = contentInsets;
yourTableView.scrollIndicatorInsets = contentInsets;
}
}
Przywróć metodę view @ keyboardWillBeHidden
func keyboardWillBeHidden(sender: NSNotification)
{
// Moving back the table view back to the default position
yourTableView.contentInset = UIEdgeInsetsZero;
yourTableView.scrollIndicatorInsets = UIEdgeInsetsZero;
}
Jeśli chcesz również uwzględnić orientację urządzenia, użyj instrukcji warunkowych, aby dostosować kod do swojego potrzeb.
// Portrait
UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.height), 0.0);
// Landscape
UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.width), 0.0);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-11 19:08:37
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
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)
}
func keyboardWillShow(_ notification:Notification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
}
}
func keyboardWillHide(_ notification:Notification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-28 13:47:30
Rozwiązanie Swift 4, którego używam, ma rozmiar klawiatury. Zastąp serverStatusStackView
dowolnym widokiem, na którym ci zależy, np.: self.view
:
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
serverStatusStackView.frame.origin.y = keyboardSize.height * 2 - serverStatusStackView.frame.height
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
serverStatusStackView.frame.origin.y += keyboardSize.height
}
}
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-15 05:58:58
Najlepszym sposobem jest użycie NotificationCenter do przechwytywania akcji klawiatury. Możesz wykonać kroki opisane w tym krótkim artykule https://medium.com/@demirciy/keyboard-handling-deb1a96a8207
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-06 08:34:58
W Swift 4.0 -
func textFieldDidBeginEditing(_ textField: UITextField) {
animateViewMoving(up: true, moveValue: 100)
}
func textFieldDidEndEditing(_ textField: UITextField) {
animateViewMoving(up: false, moveValue: 100)
}
func animateViewMoving (up:Bool, moveValue :CGFloat){
let movementDuration:TimeInterval = 0.3
let movement:CGFloat = ( up ? -moveValue : moveValue)
UIView.beginAnimations( "animateView", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration )
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
UIView.commitAnimations()
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-07 06:38:37
Swift 4.1,
Użyj klasy TPKeyBoardAvoiding, aby to osiągnąć. To działa dobrze z UIScrollView, UICollectionView, UITableView .
Po prostu Przypisz tę klasę do scrollview, collectionview lub tableview w storyboard lub utwórz jej obiekt programowo. Wszystkie pola tekstowe lub widoki tekstowe wewnątrz TPKeyboardAvoiding scrollview zostaną automatycznie dopasowane, gdy pojawi się i zniknie klawiatura.
Oto link do Tpkeyboardavoid
TPKeyboardAvoiding dla Swift 4.1,
import Foundation
import UIKit
// MARK: - TableView
class TPKeyboardAvoidingTableView:UITableView,UITextFieldDelegate, UITextViewDelegate {
override var frame:CGRect{
willSet{
super.frame = frame
}
didSet{
if hasAutomaticKeyboardAvoidingBehaviour() {return}
TPKeyboardAvoiding_updateContentInset()
}
}
override var contentSize:CGSize{
willSet(newValue){
if hasAutomaticKeyboardAvoidingBehaviour() {
super.contentSize = newValue
return
}
if newValue.equalTo(self.contentSize)
{
return
}
super.contentSize = newValue
self.TPKeyboardAvoiding_updateContentInset()
}
// didSet{
// self.TPKeyboardAvoiding_updateContentInset()
// }
}
override init(frame: CGRect, style: UITableViewStyle) {
super.init(frame: frame, style: style)
self.setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
override func awakeFromNib() {
setup()
}
deinit{
NotificationCenter.default.removeObserver(self)
}
func hasAutomaticKeyboardAvoidingBehaviour()->Bool
{
if #available(iOS 8.3, *) {
if self.delegate is UITableViewController
{
return true
}
}
return false
}
func focusNextTextField()->Bool
{
return self.TPKeyboardAvoiding_focusNextTextField()
}
@objc func scrollToActiveTextField()
{
return self.TPKeyboardAvoiding_scrollToActiveTextField()
}
override func willMove(toSuperview newSuperview: UIView?) {
super.willMove(toSuperview: newSuperview)
if newSuperview != nil {
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), object: self)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.TPKeyboardAvoiding_findFirstResponderBeneathView(self)?.resignFirstResponder()
super.touchesEnded(touches, with: event)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if !self.focusNextTextField()
{
textField.resignFirstResponder()
}
return true
}
override func layoutSubviews() {
super.layoutSubviews()
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), object: self)
Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), userInfo: nil, repeats: false)
}
}
private extension TPKeyboardAvoidingTableView
{
func setup()
{
if self.hasAutomaticKeyboardAvoidingBehaviour() { return }
NotificationCenter.default.addObserver(self,
selector: #selector(TPKeyboardAvoiding_keyboardWillShow(_:)),
name: NSNotification.Name.UIKeyboardWillChangeFrame,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(TPKeyboardAvoiding_keyboardWillHide(_:)),
name: NSNotification.Name.UIKeyboardWillHide,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(scrollToActiveTextField),
name: NSNotification.Name.UITextViewTextDidBeginEditing,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(scrollToActiveTextField),
name: NSNotification.Name.UITextFieldTextDidBeginEditing,
object: nil)
}
}
// MARK: - CollectionView
class TPKeyboardAvoidingCollectionView:UICollectionView,UITextViewDelegate {
override var contentSize:CGSize{
willSet(newValue){
if newValue.equalTo(self.contentSize)
{
return
}
super.contentSize = newValue
self.TPKeyboardAvoiding_updateContentInset()
}
// didSet{
// self.TPKeyboardAvoiding_updateContentInset()
// }
}
override var frame:CGRect{
willSet{
super.frame = frame
}
didSet{
self.TPKeyboardAvoiding_updateContentInset()
}
}
// override init(frame: CGRect) {
// super.init(frame: frame)
// }
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
setup()
}
required init?(coder aDecoder: NSCoder) {
// fatalError("init(coder:) has not been implemented")
super.init(coder: aDecoder)
self.setup()
}
override func awakeFromNib() {
setup()
}
deinit{
NotificationCenter.default.removeObserver(self)
}
func focusNextTextField()->Bool
{
return self.TPKeyboardAvoiding_focusNextTextField()
}
@objc func scrollToActiveTextField()
{
return self.TPKeyboardAvoiding_scrollToActiveTextField()
}
override func willMove(toSuperview newSuperview: UIView?) {
super.willMove(toSuperview: newSuperview)
if newSuperview != nil {
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), object: self)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.TPKeyboardAvoiding_findFirstResponderBeneathView(self)?.resignFirstResponder()
super.touchesEnded(touches, with: event)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if !self.focusNextTextField()
{
textField.resignFirstResponder()
}
return true
}
override func layoutSubviews() {
super.layoutSubviews()
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), object: self)
Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), userInfo: nil, repeats: false)
}
}
private extension TPKeyboardAvoidingCollectionView
{
func setup()
{
NotificationCenter.default.addObserver(self,
selector: #selector(TPKeyboardAvoiding_keyboardWillShow(_:)),
name: NSNotification.Name.UIKeyboardWillChangeFrame,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(TPKeyboardAvoiding_keyboardWillHide(_:)),
name: NSNotification.Name.UIKeyboardWillHide,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(scrollToActiveTextField),
name: NSNotification.Name.UITextViewTextDidBeginEditing,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(scrollToActiveTextField),
name: NSNotification.Name.UITextFieldTextDidBeginEditing,
object: nil)
}
}
// MARK: - ScrollView
class TPKeyboardAvoidingScrollView:UIScrollView,UITextFieldDelegate,UITextViewDelegate
{
override var contentSize:CGSize{
didSet{
self.TPKeyboardAvoiding_updateFromContentSizeChange()
}
}
override var frame:CGRect{
didSet{
self.TPKeyboardAvoiding_updateContentInset()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
override func awakeFromNib() {
setup()
}
func contentSizeToFit()
{
self.contentSize = self.TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames()
}
func focusNextTextField() ->Bool
{
return self.TPKeyboardAvoiding_focusNextTextField()
}
@objc func scrollToActiveTextField()
{
return self.TPKeyboardAvoiding_scrollToActiveTextField()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
deinit{
NotificationCenter.default.removeObserver(self)
}
override func willMove(toSuperview newSuperview: UIView?) {
super.willMove(toSuperview: newSuperview)
if newSuperview != nil {
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), object: self)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.TPKeyboardAvoiding_findFirstResponderBeneathView(self)?.resignFirstResponder()
super.touchesEnded(touches, with: event)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if !self.focusNextTextField()
{
textField.resignFirstResponder()
}
return true
}
override func layoutSubviews() {
super.layoutSubviews()
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), object: self)
Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), userInfo: nil, repeats: false)
}
}
private extension TPKeyboardAvoidingScrollView
{
func setup()
{
NotificationCenter.default.addObserver(self,
selector: #selector(TPKeyboardAvoiding_keyboardWillShow(_:)),
name: NSNotification.Name.UIKeyboardWillChangeFrame,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(TPKeyboardAvoiding_keyboardWillHide(_:)),
name: NSNotification.Name.UIKeyboardWillHide,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(scrollToActiveTextField),
name: NSNotification.Name.UITextViewTextDidBeginEditing,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(scrollToActiveTextField),
name: NSNotification.Name.UITextFieldTextDidBeginEditing,
object: nil)
}
}
// MARK: - Process Event
let kCalculatedContentPadding:CGFloat = 10;
let kMinimumScrollOffsetPadding:CGFloat = 20;
extension UIScrollView
{
@objc func TPKeyboardAvoiding_keyboardWillShow(_ notification:Notification)
{
guard let userInfo = notification.userInfo else { return }
guard let rectNotification = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else
{
return
}
let keyboardRect = self.convert(rectNotification.cgRectValue , from: nil)
if keyboardRect.isEmpty
{
return
}
let state = self.keyboardAvoidingState()
guard let firstResponder = self.TPKeyboardAvoiding_findFirstResponderBeneathView(self) else { return}
state.keyboardRect = keyboardRect
if !state.keyboardVisible
{
state.priorInset = self.contentInset
state.priorScrollIndicatorInsets = self.scrollIndicatorInsets
state.priorPagingEnabled = self.isPagingEnabled
}
state.keyboardVisible = true
self.isPagingEnabled = false
if self is TPKeyboardAvoidingScrollView
{
state.priorContentSize = self.contentSize
if self.contentSize.equalTo(CGSize.zero)
{
self.contentSize = self.TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames()
}
}
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Float ?? 0.0
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int ?? 0
let options = UIViewAnimationOptions(rawValue: UInt(curve))
UIView.animate(withDuration: TimeInterval(duration),
delay: 0,
options: options,
animations: { [weak self]() -> Void in
if let actualSelf = self
{
actualSelf.contentInset = actualSelf.TPKeyboardAvoiding_contentInsetForKeyboard()
let viewableHeight = actualSelf.bounds.size.height - actualSelf.contentInset.top - actualSelf.contentInset.bottom
let point = CGPoint(x: actualSelf.contentOffset.x, y: actualSelf.TPKeyboardAvoiding_idealOffsetForView(firstResponder, viewAreaHeight: viewableHeight))
actualSelf.setContentOffset(point, animated: false)
actualSelf.scrollIndicatorInsets = actualSelf.contentInset
actualSelf.layoutIfNeeded()
}
}) { (finished) -> Void in
}
}
@objc func TPKeyboardAvoiding_keyboardWillHide(_ notification:Notification)
{
guard let userInfo = notification.userInfo else { return }
guard let rectNotification = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue else
{
return
}
let keyboardRect = self.convert(rectNotification.cgRectValue , from: nil)
if keyboardRect.isEmpty
{
return
}
let state = self.keyboardAvoidingState()
if !state.keyboardVisible
{
return
}
state.keyboardRect = CGRect.zero
state.keyboardVisible = false
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Float ?? 0.0
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int ?? 0
let options = UIViewAnimationOptions(rawValue: UInt(curve))
UIView.animate(withDuration: TimeInterval(duration),
delay: 0,
options: options,
animations: { [weak self]() -> Void in
if let actualSelf = self
{
if actualSelf is TPKeyboardAvoidingScrollView {
actualSelf.contentSize = state.priorContentSize
actualSelf.contentInset = state.priorInset
actualSelf.scrollIndicatorInsets = state.priorScrollIndicatorInsets
actualSelf.isPagingEnabled = state.priorPagingEnabled
actualSelf.layoutIfNeeded()
}
}
}) { (finished) -> Void in
}
}
func TPKeyboardAvoiding_updateFromContentSizeChange()
{
let state = self.keyboardAvoidingState()
if state.keyboardVisible
{
state.priorContentSize = self.contentSize
}
}
func TPKeyboardAvoiding_focusNextTextField() ->Bool
{
guard let firstResponder = self.TPKeyboardAvoiding_findFirstResponderBeneathView(self) else { return false}
guard let view = self.TPKeyboardAvoiding_findNextInputViewAfterView(firstResponder, beneathView: self) else { return false}
Timer.scheduledTimer(timeInterval: 0.1, target: view, selector: #selector(becomeFirstResponder), userInfo: nil, repeats: false)
return true
}
func TPKeyboardAvoiding_scrollToActiveTextField()
{
let state = self.keyboardAvoidingState()
if !state.keyboardVisible { return }
let visibleSpace = self.bounds.size.height - self.contentInset.top - self.contentInset.bottom
let idealOffset = CGPoint(x: 0,
y: self.TPKeyboardAvoiding_idealOffsetForView(self.TPKeyboardAvoiding_findFirstResponderBeneathView(self),
viewAreaHeight: visibleSpace))
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double((Int64)(0 * NSEC_PER_SEC)) / Double(NSEC_PER_SEC)) {[weak self] () -> Void in
self?.setContentOffset(idealOffset, animated: true)
}
}
//Helper
func TPKeyboardAvoiding_findFirstResponderBeneathView(_ view:UIView) -> UIView?
{
for childView in view.subviews
{
if childView.responds(to: #selector(getter: isFirstResponder)) && childView.isFirstResponder
{
return childView
}
let result = TPKeyboardAvoiding_findFirstResponderBeneathView(childView)
if result != nil
{
return result
}
}
return nil
}
func TPKeyboardAvoiding_updateContentInset()
{
let state = self.keyboardAvoidingState()
if state.keyboardVisible
{
self.contentInset = self.TPKeyboardAvoiding_contentInsetForKeyboard()
}
}
func TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames() ->CGSize
{
let wasShowingVerticalScrollIndicator = self.showsVerticalScrollIndicator
let wasShowingHorizontalScrollIndicator = self.showsHorizontalScrollIndicator
self.showsVerticalScrollIndicator = false
self.showsHorizontalScrollIndicator = false
var rect = CGRect.zero
for view in self.subviews
{
rect = rect.union(view.frame)
}
rect.size.height += kCalculatedContentPadding
self.showsVerticalScrollIndicator = wasShowingVerticalScrollIndicator
self.showsHorizontalScrollIndicator = wasShowingHorizontalScrollIndicator
return rect.size
}
func TPKeyboardAvoiding_idealOffsetForView(_ view:UIView?,viewAreaHeight:CGFloat) -> CGFloat
{
let contentSize = self.contentSize
var offset:CGFloat = 0.0
let subviewRect = view != nil ? view!.convert(view!.bounds, to: self) : CGRect.zero
var padding = (viewAreaHeight - subviewRect.height)/2
if padding < kMinimumScrollOffsetPadding
{
padding = kMinimumScrollOffsetPadding
}
offset = subviewRect.origin.y - padding - self.contentInset.top
if offset > (contentSize.height - viewAreaHeight)
{
offset = contentSize.height - viewAreaHeight
}
if offset < -self.contentInset.top
{
offset = -self.contentInset.top
}
return offset
}
func TPKeyboardAvoiding_contentInsetForKeyboard() -> UIEdgeInsets
{
let state = self.keyboardAvoidingState()
var newInset = self.contentInset;
let keyboardRect = state.keyboardRect
newInset.bottom = keyboardRect.size.height - max(keyboardRect.maxY - self.bounds.maxY, 0)
return newInset
}
func TPKeyboardAvoiding_viewIsValidKeyViewCandidate(_ view:UIView)->Bool
{
if view.isHidden || !view.isUserInteractionEnabled {return false}
if view is UITextField
{
if (view as! UITextField).isEnabled {return true}
}
if view is UITextView
{
if (view as! UITextView).isEditable {return true}
}
return false
}
func TPKeyboardAvoiding_findNextInputViewAfterView(_ priorView:UIView,beneathView view:UIView, candidateView bestCandidate: inout UIView?)
{
let priorFrame = self.convert(priorView.frame, to: priorView.superview)
let candidateFrame = bestCandidate == nil ? CGRect.zero : self.convert(bestCandidate!.frame, to: bestCandidate!.superview)
var bestCandidateHeuristic = -sqrt(candidateFrame.origin.x*candidateFrame.origin.x + candidateFrame.origin.y*candidateFrame.origin.y) + ( Float(fabs(candidateFrame.minY - priorFrame.minY))<Float.ulpOfOne ? 1e6 : 0)
for childView in view.subviews
{
if TPKeyboardAvoiding_viewIsValidKeyViewCandidate(childView)
{
let frame = self.convert(childView.frame, to: view)
let heuristic = -sqrt(frame.origin.x*frame.origin.x + frame.origin.y*frame.origin.y)
+ (Float(fabs(frame.minY - priorFrame.minY)) < Float.ulpOfOne ? 1e6 : 0)
if childView != priorView && (Float(fabs(frame.minY - priorFrame.minY)) < Float.ulpOfOne
&& frame.minX > priorFrame.minX
|| frame.minY > priorFrame.minY)
&& (bestCandidate == nil || heuristic > bestCandidateHeuristic)
{
bestCandidate = childView
bestCandidateHeuristic = heuristic
}
}else
{
self.TPKeyboardAvoiding_findNextInputViewAfterView(priorView, beneathView: view, candidateView: &bestCandidate)
}
}
}
func TPKeyboardAvoiding_findNextInputViewAfterView(_ priorView:UIView,beneathView view:UIView) ->UIView?
{
var candidate:UIView?
self.TPKeyboardAvoiding_findNextInputViewAfterView(priorView, beneathView: view, candidateView: &candidate)
return candidate
}
@objc func TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_ obj: AnyObject)
{
func processWithView(_ view: UIView) {
for childView in view.subviews
{
if childView is UITextField || childView is UITextView
{
self.TPKeyboardAvoiding_initializeView(childView)
}else
{
self.TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(childView)
}
}
}
if let timer = obj as? Timer, let view = timer.userInfo as? UIView {
processWithView(view)
}
else if let view = obj as? UIView {
processWithView(view)
}
}
func TPKeyboardAvoiding_initializeView(_ view:UIView)
{
if let textField = view as? UITextField,
let delegate = self as? UITextFieldDelegate, textField.returnKeyType == UIReturnKeyType.default &&
textField.delegate !== delegate
{
textField.delegate = delegate
let otherView = self.TPKeyboardAvoiding_findNextInputViewAfterView(view, beneathView: self)
textField.returnKeyType = otherView != nil ? .next : .done
}
}
func keyboardAvoidingState()->TPKeyboardAvoidingState
{
var state = objc_getAssociatedObject(self, &AssociatedKeysKeyboard.DescriptiveName) as? TPKeyboardAvoidingState
if state == nil
{
state = TPKeyboardAvoidingState()
self.state = state
}
return self.state!
}
}
// MARK: - Internal object observer
internal class TPKeyboardAvoidingState:NSObject
{
var priorInset = UIEdgeInsets.zero
var priorScrollIndicatorInsets = UIEdgeInsets.zero
var keyboardVisible = false
var keyboardRect = CGRect.zero
var priorContentSize = CGSize.zero
var priorPagingEnabled = false
}
internal extension UIScrollView
{
fileprivate struct AssociatedKeysKeyboard {
static var DescriptiveName = "KeyBoard_DescriptiveName"
}
var state:TPKeyboardAvoidingState?{
get{
let optionalObject:AnyObject? = objc_getAssociatedObject(self, &AssociatedKeysKeyboard.DescriptiveName) as AnyObject?
if let object:AnyObject = optionalObject {
return object as? TPKeyboardAvoidingState
} else {
return nil
}
}
set{
objc_setAssociatedObject(self, &AssociatedKeysKeyboard.DescriptiveName, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-21 05:54:01
Jeśli nie masz nic przeciwko użyciu biblioteki Objective - C w swoim projekcie Swift, być może możesz użyć tego helpera . Jest to również przykład szybkiego użycia.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-14 20:27:58