webentwicklung-frage-antwort-db.com.de

UIKeyboardBoundsUserInfoKey ist veraltet, was soll stattdessen verwendet werden?

Ich arbeite an einer iPad-App mit 3.2 SDK. Ich beschäftige mich damit, die Tastaturgröße zu ermitteln, um zu verhindern, dass sich meine Textfelder dahinter verstecken. 

Ich erhalte eine Warnung in Xcode -> UIKeyboardBoundsUserInfoKey ist veraltet. Was soll ich stattdessen verwenden, um diese Warnung nicht zu erhalten?

49
Mikeware

Ich habe mit der zuvor angebotenen Lösung gespielt, hatte aber noch Probleme. Hier ist, was ich stattdessen kam:

    - (void)keyboardWillShow:(NSNotification *)aNotification {
    [self moveTextViewForKeyboard:aNotification up:YES];
}

    - (void)keyboardWillHide:(NSNotification *)aNotification {
        [self moveTextViewForKeyboard:aNotification up:NO]; 
    }

- (void) moveTextViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up{
NSDictionary* userInfo = [aNotification userInfo];

// Get animation info from userInfo
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;

CGRect keyboardEndFrame;

[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];


[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];


// Animate up or down
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];

CGRect newFrame = textView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];

newFrame.Origin.y -= keyboardFrame.size.height * (up? 1 : -1);
textView.frame = newFrame;

[UIView commitAnimations];
}
87
Jay

Aus der Dokumentation für UIKeyboardBoundsUserInfoKey:

Der Schlüssel für ein NSValue-Objekt, das ein CGRect enthält, das das Begrenzungsrechteck der Tastatur in Fensterkoordinaten angibt. Dieser Wert reicht aus, um die Größe der Tastatur zu ermitteln. Wenn Sie den Ursprung der Tastatur (vor oder nach der Animation) auf dem Bildschirm anzeigen möchten, verwenden Sie die Werte aus dem Benutzerinformationswörterbuch über die Konstanten UIKeyboardCenterBeginUserInfoKey oder UIKeyboardCenterEndUserInfoKey. Verwenden Sie stattdessen den Schlüssel UIKeyboardFrameBeginUserInfoKey oder UIKeyboardFrameEndUserInfoKey.

Apple empfiehlt die Implementierung einer solchen Komfortroutine (die als Kategorieaddition zu UIScreen implementiert werden kann):

+ (CGRect) convertRect:(CGRect)rect toView:(UIView *)view {
    UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *) view : [view window];
    return [view convertRect:[window convertRect:rect fromWindow:nil] fromView:nil];
}

um fensterangepasste Eigenschaften der Tastaturrahmengröße wiederherzustellen.

Ich habe einen anderen Ansatz gewählt, bei dem die Ausrichtung des Geräts überprüft wird:

CGRect _keyboardEndFrame;
[[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&_keyboardEndFrame];
CGFloat _keyboardHeight = ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown) ? _keyboardEndFrame.size.height : _keyboardEndFrame.size.width;
55
Alex Reynolds

Sie verwenden einfach diesen Code:

//NSVale *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
//instead of Upper line we can use either next line or nextest line.
//NSValue *aValue = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
NSValue *aValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];
9
iOS_User

Der folgende Code behebt ein Problem in Jays Antwort , das davon ausgeht, dass UIKeyboardWillShowNotification nicht erneut ausgelöst wird, wenn die Tastatur bereits vorhanden ist.

Wenn Sie mit der japanischen/chinesischen Tastatur schreiben, feuert iOS mit dem neuen Tastaturrahmen ein zusätzliches UIKeyboardWillShowNotification ab, obwohl die Tastatur bereits vorhanden ist. Dies führt dazu, dass die Höhe des self.textView im ursprünglichen Code ein zweites Mal verringert wird.

Dies reduziert self.textView auf fast nichts. Es ist dann unmöglich, dieses Problem zu beheben, da wir beim nächsten Schließen der Tastatur nur ein einziges UIKeyboardWillHideNotification erwarten.

Anstatt die Höhe von self.textView zu subtrahieren/zu addieren, abhängig davon, ob die Tastatur wie im ursprünglichen Code angezeigt/ausgeblendet wird, berechnet der folgende Code nur die maximal mögliche Höhe für self.textView, nachdem die Höhe der Tastatur auf dem Bildschirm abgezogen wurde.

Dies setzt voraus, dass self.textView die gesamte Ansicht des View-Controllers ausfüllt und es keine andere Unteransicht gibt, die sichtbar sein muss.

- (void)resizeTextViewWithKeyboardNotification:(NSNotification*)notif {

    NSDictionary* userInfo = [notif userInfo];
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;
    CGRect keyboardFrameInWindowsCoordinates;

    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindowsCoordinates];

    [self resizeTextViewToAccommodateKeyboardFrame:keyboardFrameInWindowsCoordinates
                             withAnimationDuration:animationDuration
                                    animationCurve:animationCurve];

}

- (void)resizeTextViewToAccommodateKeyboardFrame:(CGRect)keyboardFrameInWindowsCoordinates
                           withAnimationDuration:(NSTimeInterval)duration
                                  animationCurve:(UIViewAnimationCurve)curve
{

    CGRect fullFrame = self.view.frame;

    CGRect keyboardFrameInViewCoordinates =
    [self.view convertRect:keyboardFrameInWindowsCoordinates fromView:nil];

    // Frame of the keyboard that intersects with the view. When keyboard is
    // dismissed, the keyboard frame still has width/height, although the Origin
    // keeps the keyboard out of the screen.
    CGRect keyboardFrameVisibleOnScreen =
    CGRectIntersection(fullFrame, keyboardFrameInViewCoordinates);

    // Max frame availble for text view. Assign it to the full frame first
    CGRect newTextViewFrame = fullFrame;

    // Deduct the the height of any keyboard that's visible on screen from
    // the height of the text view
    newTextViewFrame.size.height -= keyboardFrameVisibleOnScreen.size.height;

    if (duration)
    {
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:duration];
        [UIView setAnimationCurve:curve];
    }

    // Adjust the size of the text view to the new one
    self.textView.frame = newTextViewFrame;

    if (duration)
    {
        [UIView commitAnimations];
    }

}

Vergessen Sie auch nicht, die Tastaturbenachrichtigungen in viewDidLoad zu registrieren:

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSNotificationCenter* notifCenter = [NSNotificationCenter defaultCenter];

    [notifCenter addObserver:self selector:@selector(resizeTextViewWithKeyboardNotification:) name:UIKeyboardWillShowNotification object:nil];
    [notifCenter addObserver:self selector:@selector(resizeTextViewWithKeyboardNotification:) name:UIKeyboardWillHideNotification object:nil];
}

Teilen des Codes zur Größenänderung in zwei Teile

Der Grund, warum der TextView-Code zur Größenänderung in zwei Teile aufgeteilt ist (resizeTextViewWithKeyboardNotification: und resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve:), besteht darin, ein anderes Problem zu beheben, wenn die Tastatur durch einen Push von einem Ansichts-Controller zu einem anderen fortgesetzt wird (siehe Wie erkenne ich die iOS-Tastatur, wenn sie nicht aktiv ist zwischen Steuerungen? ).

Da die Tastatur bereits vor dem Drücken des View-Controllers vorhanden ist, werden von iOS keine zusätzlichen Tastaturbenachrichtigungen generiert, und daher kann die Größe von textView auf der Grundlage dieser Tastaturbenachrichtigungen nicht geändert werden.

Der obige Code (sowie der ursprüngliche Code), der self.textView ändert, funktioniert daher nur, wenn die Tastatur angezeigt wird, nachdem die Ansicht geladen wurde.

Meine Lösung ist, ein Singleton zu erstellen, das die letzten Tastaturkoordinaten speichert. Rufen Sie auf - viewDidAppear: des viewControllers Folgendes auf:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // Resize the view if there's any keyboard presence before this
    // Only call in viewDidAppear as we are unable to convertRect properly
    // before view is shown
    [self resizeViewToAccommodateKeyboardFrame:[[UASKeyboard sharedKeyboard] keyboardFrame]
                         withAnimationDuration:0
                                animationCurve:0];
}

UASKeyboard ist mein Einzelgänger hier. Idealerweise sollten wir dies in - viewWillAppear: aufrufen. Nach meiner Erfahrung (zumindest unter iOS 6) konvertiert die convertRect:fromView:-Methode, die wir in resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve: verwenden müssen, den Tastaturrahmen nicht ordnungsgemäß in die Ansichtskoordinaten, bevor die Ansicht vollständig sichtbar ist.

3
junjie

Verwenden Sie einfach den Schlüssel UIKeyboardFrameBeginUserInfoKey oder UIKeyboardFrameEndUserInfoKey anstelle von UIKeyboardBoundsUserInfoKey.

2
Anand Mishra

@ Jason, du gibst einen Code ein, außer für einen Punkt.

Im Moment animieren Sie nicht wirklich etwas und die Ansicht wird einfach auf die neue Größe hochgefahren.

Sie müssen einen Zustand angeben, aus dem animiert werden soll. Eine Animation ist eine Art (vom Zustand) -> (Zustand).

Glücklicherweise gibt es eine sehr bequeme Methode, um den aktuellen Status der Ansicht als (von Status) anzugeben.

[UIView setAnimationBeginsFromCurrentState:YES];

Wenn Sie diese Zeile direkt nach beginAnimations: context hinzufügen, funktioniert Ihr Code einwandfrei. 

1
Thomas
- (CGSize)keyboardSize:(NSNotification *)aNotification {
    NSDictionary *info = [aNotification userInfo];
    NSValue *beginValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];

    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

    CGSize keyboardSize;
    if ([UIKeyboardDidShowNotification isEqualToString:[aNotification name]]) {
        _screenOrientation = orientation;
        if (UIDeviceOrientationIsPortrait(orientation)) {
            keyboardSize = [beginValue CGRectValue].size;
        } else {
            keyboardSize.height = [beginValue CGRectValue].size.width;
            keyboardSize.width = [beginValue CGRectValue].size.height;
        }
    } else if ([UIKeyboardDidHideNotification isEqualToString:[aNotification name]]) {
        // We didn't rotate
        if (_screenOrientation == orientation) {
            if (UIDeviceOrientationIsPortrait(orientation)) {
                keyboardSize = [beginValue CGRectValue].size;
            } else {
                keyboardSize.height = [beginValue CGRectValue].size.width;
                keyboardSize.width = [beginValue CGRectValue].size.height;
            }
        // We rotated
        } else if (UIDeviceOrientationIsPortrait(orientation)) {
            keyboardSize.height = [beginValue CGRectValue].size.width;
            keyboardSize.width = [beginValue CGRectValue].size.height;
        } else {
            keyboardSize = [beginValue CGRectValue].size;
        }
    }


    return keyboardSize;
}
0
karim

Es hat so funktioniert

Dies ist die Einschränkung der unteren Schaltfläche der Schaltfläche "Speichern"

@IBOutlet weak var saveBtnBottom: NSLayoutConstraint!
@IBOutlet weak var nameText: UITextField!

Inside viewDidLoad

NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
nameText.delegate = self

Dies sind die Funktionen, die wir brauchen

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


@objc func keyBoardWillShow(notification: Notification){
    if let userInfo = notification.userInfo as? Dictionary<String, AnyObject>{
        let frame = userInfo[UIResponder.keyboardFrameEndUserInfoKey]
        let keyBoardRect = frame?.cgRectValue
        if let keyBoardHeight = keyBoardRect?.height {
            self.saveBtnBottom.constant = keyBoardHeight 

            UIView.animate(withDuration: 0.5, animations: {
                self.view.layoutIfNeeded()
            })
        }
    }
}

@objc func keyBoardWillHide(notification: Notification){
    self.saveBtnBottom.constant = 30.0
    UIView.animate(withDuration: 0.5, animations: {
        self.view.layoutIfNeeded()
    })
}
0