Подтвердить что ты не робот

Перемещение панели с помощью UIScrollViewKeyboardDismissModeInteractive

У меня есть текстовое поле, которое я привязываю к вершине клавиатуры. Я не могу использовать inputAccessoryView, поскольку он всегда отображается. Я могу наблюдать за клавиатурой скрытые/показанные уведомления, чтобы перемещать ее вверх и вниз с помощью клавиатуры, но это, похоже, не работает с UIScrollViewKeyboardDismissModeInteractive. Есть ли способ получить постоянную обратную связь по позиции клавиатуры для синхронизации анимации?

4b9b3361

Ответ 1

Изменить: похоже, что это не работает в iOS 8, ребята - Извините! Я также ищу новое решение

Я решил это, создав невидимый inputAccessoryView.

textView.inputAccessoryView = [[MJXObservingInputAccessoryView alloc] init];

Аксессуар просматривает свой кадр супервизора и отправляет уведомление, которое вы можете сопоставить.

static NSString * const MJXObservingInputAccessoryViewSuperviewFrameDidChangeNotification = @"MJXObservingInputAccessoryViewSuperviewFrameDidChangeNotification";

@interface MJXObservingInputAccessoryView : UIView @end

@implementation MJXObservingInputAccessoryView

- (void)willMoveToSuperview:(UIView *)newSuperview
{
    if (self.superview)
    {
        [self.superview removeObserver:self
                            forKeyPath:@"frame"];
    }

    [newSuperview addObserver:self
                   forKeyPath:@"frame"
                      options:0
                      context:NULL];

    [super willMoveToSuperview:newSuperview];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if (object == self.superview && [keyPath isEqualToString:@"frame"])
    {
        [[NSNotificationCenter defaultCenter] postNotificationName:MJXObservingInputAccessoryViewSuperviewFrameDidChangeNotification
                                                            object:self];
    }
}

@end

Ответ 2

Я нашел решение (хотя и немного взломанное), где я реализую scrollViewDidScroll для прослушивания panGestureRecognizer, встроенного в UITableView. Оказывается, верх клавиатуры отлично сочетается с пальцем по всему жесту, поэтому вы можете просто постоянно обновлять текстовое поле, чтобы оставаться чуть выше панировочного пальца.

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {

    CGPoint fingerLocation = [scrollView.panGestureRecognizer locationInView:scrollView];
    CGPoint absoluteFingerLocation = [scrollView convertPoint:fingerLocation toView:self.view];

    if (_keyboardIsOpen && scrollView.panGestureRecognizer.state == UIGestureRecognizerStateChanged && absoluteFingerLocation.y >= (self.view.frame.size.height - _keyboardFrame.size.height)) {

        [UIView animateWithDuration:.05 animations:^{
            //This is an autolayout constraint that needs to be set to the distance between the top of the keyboard and the bottom of the screen (with a buffer of 3)
            _bottomViewVerticalSpacingConstraint.constant = [[UIScreen mainScreen] bounds].size.height - absoluteFingerLocation.y - 3;
            [self.view layoutIfNeeded];
        }];
    }
}

Затем я также регистрируюся для уведомлений

 [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShown:)
                                             name:UIKeyboardWillShowNotification object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillBeHidden:)
                                             name:UIKeyboardWillHideNotification object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillChangeFrame:)
                                             name:UIKeyboardWillChangeFrame object:nil];

И обрабатывайте их так:

-(void)keyboardWillShown:(NSNotification*)aNotification
{
    _keyboardIsOpen = YES;
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    [UIView animateWithDuration:.05 animations:^{
        _bottomViewVerticalSpacingConstraint.constant = kbSize.height;
        [self.view layoutIfNeeded];
    }];
}


-(void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    _keyboardIsOpen = NO;
    [UIView animateWithDuration:.3 animations:^{
        _bottomViewVerticalSpacingConstraint.constant = 0;
        [self.view layoutIfNeeded];
    }];
}

-(void)keyboardWillChangeFrame:(NSNotification*)aNotification {
    NSDictionary* info = [aNotification userInfo];
    _keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
}

Ответ 3

Ответ на Malcolm будет работать для iOS 8 и 7 с незначительной настройкой. У меня недостаточно репутации, чтобы комментировать его сообщение, поэтому он добавлен в качестве вики сообщества для людей, нуждающихся в решении, которое работает для iOS 7 и 8.

Заголовок

#import <UIKit/UIKit.h>

static NSString *const SSObservingInputAccessoryViewFrameDidChangeNotification = @"SSObservingInputAccessoryViewFrameDidChangeNotification";

@interface SSObservingInputAccessoryView : UIView

@end

Реализация

#import "SSObservingInputAccessoryView.h"

@implementation SSObservingInputAccessoryView

- (void)willMoveToSuperview:(UIView *)newSuperview {
    if (self.superview) {
        [self.superview removeObserver:self
                            forKeyPath:@"center"];

        [self.superview removeObserver:self
                            forKeyPath:@"frame"];
    }

    [newSuperview addObserver:self
                   forKeyPath:@"center"
                      options:0
                      context:nil];

    [newSuperview addObserver:self
                   forKeyPath:@"frame"
                      options:0
                      context:nil];

    [super willMoveToSuperview:newSuperview];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (object == self.superview
        && ([keyPath isEqualToString:@"center"] || [keyPath isEqualToString:@"frame"])) {
        [[NSNotificationCenter defaultCenter] postNotificationName:SSObservingInputAccessoryViewFrameDidChangeNotification
                                                            object:self];
    }
}

@end

Ответ 4

Вы пробовали DAKeyboardControl?

   UIView *addCommentContainer = self.addCommentContainer;
   [self.view addKeyboardPanningWithActionHandler:^(CGRect keyboardFrameInView) {
      [addCommentContainer setY:keyboardFrameInView.origin.y - addCommentContainer.frame.size.height];
   }];

Вы можете увидеть исходный код для обработки рамки клавиатуры на этом элементе управления.

Ответ 5

Только позиция CALayer обновляется интерактивно для Swift 4 на iPhone X iOS 11.2.2:

class MyValueObservingView: UIView {
    static let CALayerPositionChangeNotification = Notification.Name("CALayerPositionChangeNotification")
    static let CALayerPositionUserInfoKey = "position"

    override func willMove(toSuperview newSuperview: UIView?) {
        superview?.layer.removeObserver(self, forKeyPath: type(of: self).CALayerPositionUserInfoKey)
        newSuperview?.layer.addObserver(self, forKeyPath: type(of: self).CALayerPositionUserInfoKey, options: [.initial, .new], context: nil)
        super.willMove(toSuperview: newSuperview)
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == type(of: self).CALayerPositionUserInfoKey, let position = change?[.newKey] as? CGPoint {
//            print("MyValueObservingView layer position changed to \(position)")
            NotificationCenter.default.post(name: type(of: self).CALayerPositionChangeNotification, object: self, userInfo: [type(of: self).CALayerPositionUserInfoKey: position])
        } else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        }
    }
}

Ответ 6

Там гораздо более простой способ привязать что-то к клавиатуре. Вам просто нужно реализовать эти методы, и iOS справится с этим для вас.

- (UIView *) inputAccessoryView {
     // Return your textfield, buttons, etc
}

- (BOOL) canBecomeFirstResponder {
    return YES;
}

Вот хороший учебник, разбивающий его больше

Ответ 7

Это работает для меня:

Регистрация для клавиатуры скрывает уведомление: UIKeyboardDidHideNotification.

В viewDidLoad добавьте панель инструментов в нижнюю часть представления, используя addSubview.

Я использую textView, поэтому в textViewShouldBeginEditing я устанавливаю inputAccessoryView.

Затем на клавиатуре был скрыт метод, отрегулируйте рамку на панели инструментов, установите для параметра InputAccessoryView значение nil и ВАЖНО, добавьте панель инструментов в качестве подсмотра представления снова.