UIKeyboardAppearance в UIWebView

С iOS7 мы увидели введение UIKeyboardAppearance. Отлично работает при применении к UITextView, но, как Apple утверждает, UIWebView не соответствует протоколу UITextInputTraits.

Хотя класс UIWebView не поддерживает протокол UITextInputTraits напрямую, вы можете настроить некоторые атрибуты клавиатуры для элементов ввода текста. Например, вы можете включить атрибуты autocorrect и auto-capitalization в определении входного элемента для указания поведения клавиатуры, как показано в следующем примере.

Кто-нибудь еще выяснил магический атрибут HTML, чтобы установить внешний вид клавиатуры? Или нет? Любое обходное решение? (Нет частных API, пожалуйста)

Ответ 1

Очень простым решением было бы добавить метод - (UIKeyboardAppearance) keyboardAppearance через расширение категории до UIView. В этом методе вы можете просто вернуть UIKeyboardAppearanceDark. Это работает, потому что метод будет волшебным образом добавлен во внутренний вид UIWebView (UIWebBrowserView), который становится первым ответчиком, когда пользователь вступает в поле ввода формы HTML. Основная проблема с этим подходом заключается в том, что он повлияет на все виды, полученные из UIView, что может быть нежелательно.

Мы можем построить более целенаправленное решение, которое перехватывает первый ответчик, отвечающий за клавиатуру, и добавляет к нему метод keyboardAppearance, если он не существует. Это ухудшится изящно, если внутренняя реализация UIWebBrowserView изменится в будущем на включение селектора keyboardAppearance.

#import <objc/runtime.h>

@protocol TSPingPong <NSObject>
- (void) ts_pong: (id) sender;
@end

@interface NSObject (TSPingPong)
@end
@implementation NSObject (TSPingPong)
- (void) ts_ping: (id) sender
{
    if ( [sender respondsToSelector: @selector(ts_pong:)] )
    {
        [sender performSelector: @selector( ts_pong: ) withObject: self ];
    }
}
@end

@implementation TSViewController
{
    IBOutlet UIWebView* _webView;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

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

    NSString* html = @"<br><br><br><form action=''> " \
    "First name: <input type='text'><br> " \
    "Last name: <input type='text'><br>" \
    "<input type='submit' value='Submit'> " \
    "</form>";

    [_webView loadHTMLString: html
                     baseURL: nil];
}

- (void) keyboardWillAppear: (NSNotification*) n
{
    // the keyboard is about to appear!
    // play pingpong with the first responder so we can ensure it has a keyboardAppearance method:

    [[UIApplication sharedApplication] sendAction: @selector( ts_ping:) // added via category extension
                                               to: nil                  // to: the first responder
                                             from: self                 // "sender"
                                         forEvent: nil];
}

- (void) ts_pong: (id) sender
{
    // sender is the first responder.  Happens to be undocumented "UIWebBrowserView" in this case.

    // if it doesn't have it own keyboardAppearance method then let add one:
    if ( ![sender respondsToSelector: @selector(keyboardAppearance)] )
    {
        Method m = class_getInstanceMethod( [self class], @selector( keyboardAppearanceTemplateMethod ) );

        IMP imp = method_getImplementation( m );

        const char* typeEncoding = method_getTypeEncoding( m );

        class_addMethod( [sender class], @selector(keyboardAppearance), imp, typeEncoding );
    }
}

- (UIKeyboardAppearance) keyboardAppearanceTemplateMethod
{
    return UIKeyboardAppearanceDark;
}

@end