InputAccessoryView zadokowany na dole

Próbuję osiągnąć podobne zachowanie pozycjonowania, jak dolny pasek wprowadzania tekstu w aplikacji Wiadomości Apple.

Próbowałem wielu podejść, Szukałem wysoko i nisko i jest wiele podobnych pytań, ale żadne nie były zadowalające.

Aby określić:

  1. jest UIToolbar na dole widoku
  2. pasek narzędzi ma podążać za klawiaturą, gdy pojawi się i zniknie klawiatura
  3. pasek narzędzi powinien pozostać na górze klawiatury, gdy klawiatura jest widoczna
  4. Gdy klawiatura jest ukryta, pasek narzędzi pozostaje ("zadokowany") u dołu widoku

Proponowane rozwiązania:

Ręcznie Animuj pasek narzędzi w odpowiedzi na powiadomienia o wyglądzie klawiatury

To rozwiązanie nie spełnia specjalnego przypadku drugiego wymogu ( pasek narzędzi ma podążać za klawiaturą, gdy pojawi się i zniknie klawiatura):

    W iOS 7 wprowadzono UIScrollViewKeyboardDismissMode. Umożliwia interaktywny gest do zwalniania klawiatury. Gdy użytkownik przesuwa się poza górną krawędź klawiatury, ramka klawiatury stopniowo podąża za nią. To rozwiązanie nie robi nic, aby dostosować to zachowanie i po prostu pozostawia pasek narzędzi zablokowany w jego animowanej pozycji.

Ponadto rozwiązanie to nie spełnia również specjalnego przypadku trzeciego wymogu ( pasek narzędzi powinien pozostać na górze klawiatury, gdy klawiatura jest widoczna):

  • rotacja. To rozwiązanie wymaga dodatkowego, irytująco zewnętrznego kodu (jak zobaczymy w następnym proponowanym rozwiązaniu), aby obrócić pasek narzędzi w odpowiedzi na obrót urządzenia.

Kolejny problem z tym rozwiązaniem:

  • wysokość klawiatury. Dzięki takiemu rozwiązaniu pasek narzędzi nie jest zakładany jako część wysokości klawiatury, dlatego należy napisać dodatkowy kod, aby ułatwić prawidłowe wstawianie treści.

Następne proponowane rozwiązanie:

Użyj UIResponder's inputAccessoryView

[9]}To rozwiązanie wydaje się być sposobem, w jaki Apple zamierzało wspierać tego rodzaju zachowania, ponieważ rozwiązuje wszystkie niedociągnięcia związane z ręcznym animowaniem paska narzędzi. Ale to rozwiązanie całkowicie pomija czwarte Wymaganie ( gdy klawiatura jest ukryta, pasek narzędzi pozostaje ("zadokowany") u dołu widoku ).

Wydaje się, że rozwiązaniem jest użycie UIResponder ' s inputAccessoryView, ale w jakiś sposób sprawia, że inputAccessoryView nie porusza się poniżej widoku. Szukam czystego kodu, aby to osiągnąć. Istnieją wyszukane, niemal szlachetne, próby gdzie indziej, ale jak wspomniano, nie spełniają one wymagań.

W moim konkretnym przypadku chcę użyć paska narzędzi UINavigationController, który pociąga za sobą dodatkowe problemy, ponieważ nie jest to zamierzone zachowanie dla UINavigationController. Bez względu na to, jestem gotów wprowadzić kilka hakerskich poprawek, aby to osiągnąć.

Author: Stian Høiland, 2013-11-04

5 answers

Właśnie pokazałem "rozwiązanie" Jason Foreman (@threeve). Na kontrolerze widoku (tak, kontroler widoku) dodaj inputAccessoryView: i zwróć widok, który chcesz zadokować na dole i przesuwać za pomocą klawiatury. To po prostu działa. Widok nie musi znajdować się w hierarchii widoku, zostanie on automatycznie wstawiony przez kontroler widoku.

Edit: zaimplementuj również canBecomeFirstResponder i zwróć Yes (jak zauważył Max Seelemann). reloadInputViews może być również przydatne.

 55
Author: Jonathan Badeen,
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-10 23:25:18

Rozwiązanie Jonathana Badeena zadziałało dla mnie. Oto kod z Arik pokazujący, jak go zaimplementować (powinno to wejść w odpowiedni kontroler widoku):

    - (BOOL)canBecomeFirstResponder{

        return YES;

    }

    - (UIView *)inputAccessoryView{

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

    }
 31
Author: Russ Hooper,
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-05-23 12:03:03

Dla szukających wersji Swift:

Podłącz swój pasek narzędzi (w moim przypadku 'myToolBar') do kontrolera widoku. Następnie nadpisuje metodę canBecomeFirstResponder i nadpisuje zmienną getter inputAccessoryView. Również nie zapomnij dodać self.myToolBar.removeFromSuperview() lub xcode będzie narzekać.

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()
    }
}
 6
Author: jonprasetyo,
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-06-25 17:24:26

Istnieje doskonałe, łatwe do wdrożenia, open-source rozwiązanie od dobrych ludzi w Slack: SlackTextViewController.

Oto jak zaimplementować widok z zadokowanym paskiem narzędzi w czterech krokach:

  1. zainstaluj pod w swoim projekcie. ( http://cocoapods.org/?q=SlackTextViewController )
  2. jeśli piszesz aplikację w języku Swift, Utwórz nagłówek łączący Kod Swift z klasami Obj-C. Oto miły szybki walkthrough on that . (Nagłówek pomostowy nie będzie potrzebny, gdy klasy zostaną przetłumaczone na Swift, ktoś chce nad tym współpracować?)
  3. Utwórz MessageViewController, który dziedziczy z SLKTextViewController, nie musisz pisać więcej kodu niż ten:

    import Foundation
    import UIKit
    
    class MessageViewController: SLKTextViewController {
    
        required init(coder aDecoder: NSCoder!) {
            super.init(coder: aDecoder)
        }
    }
    
  4. W Storyboard Utwórz kontroler widoku, który dziedziczy z MessageViewController.
  5. przetestuj aplikację na urządzeniu lub emulatorze, zobaczysz piękny zadokowany pasek podręczny, który również (jako bonus) rozszerza się, gdy użytkownik pisze dodatkowe wiersze tekstu.

Rekwizyty dla zespołu Slack za wydobycie tak użytecznej kapsuły.

 5
Author: Alex Soble,
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-10-20 14:00:41

Więc wiem, że to jest stary post i nie jestem pewien, czy to rozwiązałeś, czy nie, ale znalazłem sposób, aby to działa. Wierzę, że jest błąd w inputAccessoryView, ale stworzyłem hacky rozwiązanie, aby zachowywać się tak, jak aplikacja wiadomości robi. Myślę, że podałem cały kod niezbędny do wdrożenia obejścia. Zamierzam spróbować uzyskać bardziej odpowiedni post na blogu stworzony w niedalekiej przyszłości, z bardziej dogłębnym opisem z moimi ustaleniami. Wszelkie pytania, pozwól mi wiedzieć.

@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
Author: daltoniam,
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
2013-12-24 05:11:28