Adding Speech to custom UIMenuController

后端 未结 2 2185
陌清茗
陌清茗 2021-02-15 12:33

I created a custom UIMenuController in a UIWebView but it seems to get rid of the \"Speak Selection\" option in the UIMenuController after

相关标签:
2条回答
  • 2021-02-15 13:13

    Some of the UIMenuController items can be found in UIResponder.h in UIKit framework.

    @interface NSObject(UIResponderStandardEditActions)   // these methods are not implemented     in NSObject
    
     - (void)cut:(id)sender __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);
     - (void)copy:(id)sender __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);
     - (void)paste:(id)sender __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);
     - (void)select:(id)sender __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);
     - (void)selectAll:(id)sender __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);
     - (void)delete:(id)sender __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_2);
     - (void)makeTextWritingDirectionLeftToRight:(id)sender __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0);
     - (void)makeTextWritingDirectionRightToLeft:(id)sender __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0);
    
     @end
    

    But there is no speak text option there. It turns out if you override "canPerformAction: WithSelector:", within a subclass of your UIWebView or UITextField as listed below, you will also get a listing of all of the actions sent to self including the UIMenuController options.

    // Override
    - (BOOL) canPerformAction:(SEL)action withSender:(id)sender
    {
        NSLog(@"%@",NSStringFromSelector(action));
    
        //if you are customizing your menu, return NO except for your specific selectors
        return YES;
    }
    

    You'll find several methods that may interest you, including _accessibilitySpeak: and _accessibilityPauseSpeaking: and _define: (please note these three selectors are iOS 5 only). The underscore means that they are private, so also keep in mind that you can't directly call them with the classic [class selector] syntax.

    Remember, these are system menuItems, which means Apple will stick them in front of any menu items you add, often leaving your menu items in a second layer accessed by tapping the > arrow. If you want to control the order in which the items are display, and/or mix Apple's system items with your items, you will need to create custom menu items for these actions that call a method in your class like this:

    - (void) myAppSpeak: (UIMenuController*) sender
    {
        [super performSelector:@selector(_accessibilitySpeak:)];
    }
    

    Keep in mind that these methods need to be implemented in a subclass of a class that implements these already, such as a sub class of UIWebView....not a subclass of UIWebViewController.

    Then inside the controller, or wherever you build your UIMenuController, create the custom button that calls this method. Be sure if you are in a web view, you are referencing an object of type of your subclass, and not the generic webview. Otherwise, it won't work.

        UIMenuItem *speakMenuItem = [[UIMenuItem alloc] initWithTitle:@"Speak" action:@selector(myAppSpeak:)];
    
        [UIMenuController sharedMenuController].menuItems = [NSArray arrayWithObjects:speakMenuItem, etc. etc., nil];
    

    Even though you are adding it to the your menu items, it will not appear unless you return YES for the selector in your canPerformAction: WithSelector: in your subclass of your web view or text field. So feel free to add items here that may be circumstantial otherwise. You can use logic in your subclassed view to sort that out.

    0 讨论(0)
  • 2021-02-15 13:27

    I've found some interesting things with this bug. Basically, when speak selection is enabled, after you make the first selection the UIMenuController is emptied of menuItems. The solution, though hacky, is simple.

    - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    NSString *selectorString = NSStringFromSelector(action);
    BOOL isAccessibilitySelector = [selectorString isEqualToString:@"_accessibilitySpeak:"] || [selectorString isEqualToString:@"_accessibilityPauseSpeaking:"];
    if (isAccessibilitySelector && [super canPerformAction:action withSender:sender]) {
        //(re)add menuItems to UIMenuController
        return YES;
    }
    return NO;
    

    }

    I should note that you must re-add the menuItems after their canPerformAction...() has been called.

    I have submitted this as radar:12931434. Update: DUP'ed to 13060693.

    0 讨论(0)
提交回复
热议问题