InputAccessoryView состыковался внизу

Я пытаюсь добиться аналогичного поведения позиционирования, как нижняя строка ввода текста приложения Apple Messages.

Я пробовал много подходов, искал высоко и низко, и есть много похожих вопросов, но ни один из них не был удовлетворительным.

Чтобы указать:

  • В нижней части представления есть UIToolbar
  • Панель инструментов должна следовать за клавиатурой, когда клавиатура появляется и исчезает
  • Панель инструментов должна оставаться на клавиатуре, когда клавиатура видна.
  • Когда клавиатура скрыта, панель инструментов остается ( "состыкована" ) в нижней части представления

Предлагаемые решения:

Вручную оживить панель инструментов в ответ на уведомления о появлении клавиатуры

Это решение не соответствует специальному случаю второго требования (панель инструментов должна следовать за клавиатурой, когда клавиатура появляется и исчезает):

  • В iOS 7 была введена UIScrollViewKeyboardDismissMode. Это позволяет интерактивный жест для отклонения клавиатуры. Когда пользователь катится мимо верхнего края клавиатуры, постепенно меняется рамка клавиатуры. Это решение ничего не делает для размещения этого поведения и просто оставляет панель инструментов в анимированной позиции.

Кроме того, это решение также не может выполнить специальный случай третьего требования (панель инструментов должна оставаться на клавиатуре, когда клавиатура видна):

  • Вращение. Это решение требует дополнительного, досадно постороннего кода (как мы увидим в следующем предлагаемом решении) для поворота панели инструментов в ответ на вращение устройства.

Другая проблема с этим решением:

  • Высота клавиатуры. С помощью этого решения панель инструментов не считается частью высоты клавиатуры, поэтому необходимо добавить дополнительный код для обеспечения правильной вставки содержимого.

Следующее предлагаемое решение:

Используйте UIResponder inputAccessoryView

Это решение похоже на то, как Apple намерена поддерживать такое поведение, поскольку оно решает все недостатки ручной анимации панели инструментов. Но это решение полностью пропускает четвертое требование (когда клавиатура скрыта, панель инструментов остается ( "состыкована" ) в нижней части представления).


Кажется, что решение состоит в использовании UIResponder inputAccessoryView, но каким-то образом сделать inputAccessoryView не перемещаться под представлением. Я ищу чистый код для этого. Существуют продуманные, почти благородные попытки в другом месте, но, как уже упоминалось, они не отвечают требованиям.

В моем конкретном случае я использую панель инструментов UINavigationController, которая влечет за собой дополнительные проблемы, поскольку это не предназначено для UINavigationController. Независимо от того, я готов представить некоторые хакерские исправления, чтобы выполнить это.

Ответ 1

Мне просто показалось "решение" Джейсона Формана (@threeve). На контроллере представления (да, контроллер просмотра) добавьте inputAccessoryView: и верните представление, которое вы хотите состыковать внизу, и переместите его с клавиатуры. Это просто работает. Вид не обязательно должен быть в вашей иерархии представлений, он будет автоматически вставлен контроллером представления.

edit: также реализует canBecomeFirstResponder и возвращает ДА ​​(как отметил Макс Силеманн). reloadInputViews также может быть полезен.

Ответ 2

Джонатан Баден, вышеупомянутое решение работало для меня. Здесь код из Arik показывает, как его реализовать (это должно идти в вашем соответствующем контроллере представления):

    - (BOOL)canBecomeFirstResponder{

        return YES;

    }

    - (UIView *)inputAccessoryView{

        return self.inputAccessoryToolbar;  
     // where inputAccessoryToolbar is your keyboard accessory view

    }

Ответ 3

Для тех, кто ищет версию Swift:

Подключите свою панель инструментов (в моем случае "myToolBar" ) к контроллеру просмотра. Затем переопределите метод canBecomeFirstResponder и переопределите переменную getter inputAccessoryView. Также не забудьте добавить self.myToolBar.removeFromSuperview(), иначе xcode будет жаловаться.

class ViewController: UIViewController {

    @IBOutlet var myToolBar: UIToolbar!

    override func canBecomeFirstResponder() -> Bool {
        return true
    }


    override var inputAccessoryView:UIView{
        get{
            return self.myToolBar
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.myToolBar.removeFromSuperview()
    }
}

Ответ 4

Отличное, простое в использовании решение с открытым исходным кодом от хороших людей в Slack: SlackTextViewController.

Здесь, как реализовать представление с закрепленной панелью инструментов в четыре этапа:

  • Установите модуль в свой проект. (http://cocoapods.org/?q=SlackTextViewController)
  • Если вы пишете приложение в Swift, создайте заголовок для соединения между вашим кодом Swift и их классами Obj-C. Вот хорошее быстрое пошаговое руководство по этому вопросу. (Неправильный заголовок моста не понадобится, если классы переведены в Swift, кто-то хочет сотрудничать с ним?)
  • Создайте MessageViewController, который наследует от SLKTextViewController, не нужно писать больше кода, чем это:

    import Foundation
    import UIKit
    
    class MessageViewController: SLKTextViewController {
    
        required init(coder aDecoder: NSCoder!) {
            super.init(coder: aDecoder)
        }
    }
    
  • В Storyboard создайте контроллер просмотра, который наследуется от MessageViewController.
  • Проверяйте приложение на устройстве или эмуляторе, вы увидите красивый стыковочный текстовый блок, который также (в качестве бонуса) расширяется, когда пользователь пишет дополнительные строки текста.

Подходит для команды в Slack для извлечения такого полезного контейнера.

Ответ 5

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

@property(nonatomic,assign)BOOL isFirstKeyboard; //workaround for keyboard bug

@property(nonatomic,assign)BOOL isViewAppear;

@property(nonatomic,strong)ChatBarView *chatView; //custom chat bar view

@property(nonatomic,strong)UIView *footerPadView; //just to add some nice padding
////////////////////////////////////////////////////////////////////////////////////////////////////
//in the view did load
- (void)viewDidLoad
{
    //more app specific code...
    self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
    self.chatView.textView.inputAccessoryView = self.chatView;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
-(void)done
{
    self.isFirstKeyboard = YES;
    [self.chatView.textView becomeFirstResponder];
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up
{
    if(!self.isViewAppear)
        return;
    //NSLog(@"keyboard is: %@", up ? @"UP" : @"Down");
    if(!up && !self.isFirstKeyboard)
        [self performSelector:@selector(done) withObject:nil afterDelay:0.01];
    else if(!up & self.isFirstKeyboard)
    {
        self.isFirstKeyboard = NO;
        [self.view addSubview:self.chatView];
        CGRect frame = self.chatView.frame;
        frame.origin.y = self.view.frame.size.height - self.chatView.frame.size.height;
        self.chatView.frame = frame;
    }
    else
    {
        NSDictionary* userInfo = [aNotification 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];
        if(up)
            [UIView setAnimationDuration:0.2];
        else
            [UIView setAnimationDuration:0.3];
        [UIView setAnimationCurve:animationCurve];

        CGRect frame = self.footerPadView.frame;
        CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
        if (up)
            frame.size.height = keyboardFrame.size.height - self.chatView.frame.size.height;
        else
            frame.size.height = 0;
        self.footerPadView.frame = frame;
        self.tableView.tableFooterView = self.footerPadView;
        [UIView commitAnimations];
    }
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)keyboardWillShow:(NSNotification *)aNotification {
    [self moveTextViewForKeyboard:aNotification up:YES];
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)keyboardWillHide:(NSNotification *)aNotification
{
    [self moveTextViewForKeyboard:aNotification up:NO];
}
////////////////////////////////////////////////////////////////////////////////////////////////////