0

My app allows users to format text in a UITextView by using some custom formatting buttons I've created. Now I want to enable the allowsEditingTextAttributes property of the text view so that users can copy and paste formatted text between text views. This enables the bold/italic/underline buttons in the standard UIMenuController for the text view. This is fine, but when users change the formatting through this menu, I need to call my custom method that updates the state of my custom formatting buttons. How can I detect that a user has tapped one of the UIMenuController's formatting buttons?

I looked for notifications in the UITextView and UIMenuController class references, but didn't see anything relevant. These formatting buttons don't trigger a UITextViewTextDidChangeNotification and don't trigger the textViewDidChange: method of the UITextViewDelegate. I also tried subclassing the UITextView class to override a method there, but I don't know what method to override. It looks like a bold: method doesn't exist, for example, even though a paste: method does exist there. Does anyone know what method of what class is called when tapping one of the bold/italic/underline buttons?

These buttons aren't mentioned in the Text Programming Guide for iOS or the UIMenuController class reference, as far as I can tell.

Community
  • 1
  • 1
arlomedia
  • 8,534
  • 5
  • 60
  • 108
  • Have you considered using the UITextView.inputAccessoryView to display a toolbar above the keyboard rather than using the UIMenuController. This seems to be the approach Apple have taken with the new version of Pages, so you might want to consider this for consistency. If not and you wish to let me know and I will post an example, its pretty straight forward and means you don't have to mess with the default UIMenuController. – Duncan Groenewald Nov 27 '13 at 01:21
  • Although I am not sure I understand what you mean by changing the state of your buttons have you had a look at the `- (void)textStorage:(NSTextStorage *)textStorage didProcessEditing:(NSTextStorageEditActions)editedMask range:(NSRange)editedRange changeInLength:(NSInteger)delta` delegate method which should be called any time changes are made to text. – Duncan Groenewald Nov 27 '13 at 01:26
  • BTW ignore my first message, I didn't read your question properly. Have you considered removing these menu's ? – Duncan Groenewald Nov 27 '13 at 02:32
  • I did consider hiding the format buttons from the editing menu. It's nice to have them there, it just looks broken if someone sets text to bold using those buttons and my custom bold button doesn't become highlighted to reflect the change. – arlomedia Nov 27 '13 at 03:07

1 Answers1

3

This might be more helpful.

If you implement this method in UITextView subclass then you can control whether the menu options display or not. You can also check the log output to see what methods are getting called. In the example below I am disabling the text style options menu.

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    LOG(@"canPerformAction: called");
    FLOG(@" action %@", NSStringFromSelector(action));

    if (action == @selector(_showTextStyleOptions:)) {

                return NO;

    }

    return [super canPerformAction:action withSender:sender];
}

These are some of the selectors that get checked:

copy:
select:
selectAll:
paste:
delete:
_promptForReplace:
_showTextStyleOptions:  ***
_define:
etc...

If you select the Text Style Options menu then you get the following:

toggleBoldface:
toggleItalics:
toggleUnderline:

Hope this helps.

Duncan Groenewald
  • 8,496
  • 6
  • 41
  • 76
  • Brilliant! The toggleBoldFace: method is what I was looking for. I'm trying that now... – arlomedia Nov 27 '13 at 03:07
  • All right, I overrode the three "toggle" methods you found and added `[self.delegate textViewDidChange:self]` to each method. That triggers the custom method that updates the state of my custom formatting buttons, so they stay in sync with the new formatting as it is applied. It works perfectly. Thanks! – arlomedia Nov 27 '13 at 04:13
  • 1
    @arlomedia This is a late response, but what you were actually looking for is setting a delegate on NSTextStorage behind the text view. No need to override anything. – Andrey Tarantsov Aug 31 '14 at 00:58