it-swarm.com.ru

InputAccessoryView пристыкован внизу

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

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

Указать:

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

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

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

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

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

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

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

Еще одна проблема с этим решением:

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

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

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

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


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

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

46
Stian Høiland

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

Правка: также реализовать canBecomeFirstResponder и вернуть YES (как отметил Макс Зелеманн). reloadInputViews также может быть удобным.

57
Jonathan Badeen

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

    - (BOOL)canBecomeFirstResponder{

        return YES;

    }

    - (UIView *)inputAccessoryView{

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

    }
31
Russ Hooper

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

Подключите вашу панель инструментов (в моем случае "myToolBar") к вашему контроллеру представления. Затем переопределите метод canBecomeFirstResponder и переопределите переменную получения 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()
    }
}
9
jonprasetyo

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

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

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

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

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

6
Alex Soble

Так что я знаю, что это старый пост, и я не уверен, решили вы это или нет, но я нашел способ заставить это работать. Я полагаю, что есть ошибка в 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];
}
////////////////////////////////////////////////////////////////////////////////////////////////////
2
daltoniam