【问题标题】:UIKeyboardAppearance in UIWebViewUIWebView 中的 UIKeyboardAppearance
【发布时间】:2013-11-26 11:40:33
【问题描述】:

在iOS7中,我们看到了UIKeyboardAppearance的引入。应用于UITextView 时效果很好,但作为Apple statesUIWebView 不符合UITextInputTraits 协议。

虽然 UIWebView 类不直接支持 UITextInputTraits 协议,但是你可以为文本输入元素配置一些键盘属性。例如,您可以在输入元素的定义中包含自动更正和自动大写属性来指定键盘的行为,如下例所示。

有没有人想出神奇的 HTML 属性来设置键盘外观?还是没有?任何解决方法? (请不要使用私有 API)

【问题讨论】:

标签: objective-c uiwebview ios7


【解决方案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's own keyboardAppearance method then let's 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

【讨论】:

  • 整洁。向私有类动态添加方法会违反任何 Apple 规则吗?
  • @marklar - 我认为在任何规则中都没有明确指出它。但我能理解它越界的论点。如果有任何其他解决方案,我会感到惊讶(尽管我很想看到一些!)。请注意,类别扩展将实现相同的效果,而无需专门针对私有类。但它对应用程序的影响更大。
  • 我以前尝试过,但对我不起作用。浏览器视图确实包含一个特征对象,但不知何故它并没有改变键盘的外观。
  • @LeoNatan。不确定“包含特征对象”是什么意思。它可能符合 UITextInputTraits 协议 - 但该协议上的所有方法都是可选的,而且它似乎没有实现 keyboardAppearance。
  • 幕后有一个actual UITextInputTraits object,所有符合协议的类实际上都将方法调用转发给该对象。
猜你喜欢
  • 1970-01-01
  • 2014-08-04
  • 1970-01-01
  • 1970-01-01
  • 2011-08-25
  • 2013-11-07
  • 2013-11-14
  • 2011-04-14
  • 2014-02-06
相关资源
最近更新 更多