Как я могу добавить пункт меню во всплывающее меню NSTextAttachment UITextView?

Я хочу добавить еще один пункт меню к параметрам меню прикрепления изображения по умолчанию (Копировать изображение, Сохранить в фотопленке). Обратите внимание, что эти параметры отображаются при длительном нажатии на изображение, встроенное в UITextView, если textView не находится в режиме редактирования.

Я попытался добавить пользовательское меню в uimenucontroller и использовать -(void)canPerformAction для включения или отключения параметра, однако это, похоже, добавляет пункт меню в меню редактирования uitextView и не влияет на всплывающее меню вложений.

-(void)canPerformAction никогда не вызывается при длительном нажатии на вложение изображения.


person Duncan Groenewald    schedule 08.11.2013    source источник


Ответы (1)


Что ж, согласно Apple, для этого нет общедоступного API, однако, как оказалось, относительно просто заменить меню по умолчанию тем, которое выглядит и ведет себя так же.

В viewController, который содержит UITextView, добавьте следующее или подобное и настройте его как делегат textView.

- (BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment inRange:(NSRange)characterRange {

    // save in ivar so we can access once action sheet option is selected
    _attachment = textAttachment;

    [self attachmentActionSheet:(UITextView *)textView range:characterRange];

    return NO;
}
- (void)attachmentActionSheet:(UITextView *)textView range:(NSRange)range {

    // get the rect for the selected attachment (if its a big image with top not visible the action sheet
    // will be positioned above the top limit of the UITextView
    // Need to add code to adjust for this.
    CGRect attachmentRect = [self frameOfTextRange:range inTextView:textView];
      _attachmentMenuSheet = [[UIActionSheet alloc] initWithTitle:nil
                                                           delegate:self
                                                  cancelButtonTitle:@"Cancel"
                                             destructiveButtonTitle:nil
                                                  otherButtonTitles:@"Copy Image", @"Save to Camera Roll", @"Open in Viewer", nil];

    // Show the sheet
    [_attachmentMenuSheet showFromRect:attachmentRect inView:textView animated:YES];
}
- (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView {

    CGRect rect = [textView.layoutManager boundingRectForGlyphRange:range inTextContainer:textView.textContainer];

    // Now convert to textView coordinates
    CGRect rectRange = [textView convertRect:rect fromView:textView.textInputView];

    // Now convert to contentView coordinates
    CGRect rectRangeSuper = [self.contentView convertRect:rectRange fromView:textView];

    // Get the textView frame
    CGRect rectView = textView.frame;

    // Find the intersection of the two (in the same coordinate space)
    CGRect rectIntersect = CGRectIntersection(rectRangeSuper, rectView);

    // If no intersection then that's weird !!
    if (CGRectIsNull(rectIntersect)) {
        return rectRange;
    }

    // Now convert the intersection rect back to textView coordinates
    CGRect rectRangeInt = [textView convertRect:rectIntersect fromView:self.contentView];

    return rectRangeInt;
}

- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
    if (actionSheet == _attachmentMenuSheet) {
        switch (buttonIndex) {

            case 0:
                [self copyImageToPasteBoard:[_attachment image]];
                break;

            case 1:
                [self saveToCameraRoll:[_attachment image]];
                break;

            case 2:
                [self browseImage:[_attachment image]];
                break;

            default:
                break;
        }
    }
}
- (void)saveToCameraRoll:(UIImage*)image {
    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
- (void)copyImageToPasteBoard:(UIImage*)image {
    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
    NSData *data = UIImagePNGRepresentation(image);
    [pasteboard setData:data forPasteboardType:@"public.png"];
}

-(void)browseImage:(UIImage*)image
{

    OSImageViewController *_imageViewerController = [[OSImageViewController alloc] init];
    UIImage *img = [[UIImage alloc] initWithData:UIImagePNGRepresentation(image)];

    _imageViewerController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
    _imageViewerController.modalPresentationStyle = UIModalPresentationFullScreen;
    _imageViewerController.delegate = self;
    [self presentViewController:_imageViewerController animated:YES completion:^(void){
        [_imageViewerController setImage:img];

    }];

}
person Duncan Groenewald    schedule 19.11.2013
comment
Дункан, что здесь может быть self.contentView? - person Natan R.; 23.02.2014
comment
Вы должны иметь возможность использовать любой супервизор UITextView. В моем случае у меня есть прокручиваемая форма, поэтому у меня есть вид scrollView с фиксированной высотой/переменной шириной (чтобы соответствовать ширине устройств), внутри которого размещены элементы управления, включая UITextView (ы). Это я называю contentView. - person Duncan Groenewald; 24.02.2014
comment
Так было бы лучше или, в более общем смысле, вызвать 'textView.superview'? - person Natan R.; 24.02.2014
comment
Да, это должно работать, но в зависимости от вашей иерархии представлений вам может потребоваться сделать что-то другое. Проверьте здесь для получения более подробной информации, хотя я не могу вспомнить, объяснял ли я детали того, почему вам нужно найти пересечение вещей из-за частично закрытых видов, если они были прокручены. ossh.com.au/design-and-technology/software-development/ - person Duncan Groenewald; 24.02.2014
comment
Достаточно сказать, что если textView был прокручен так, что изображение частично скрыто, вы не хотите, чтобы источник всплывающего окна находился выше верхней границы textView любого другого вида отсечения (если весь контентView был прокручен вверх - не уверен, что я удовлетворил эту ситуацию в примере кода). - person Duncan Groenewald; 24.02.2014