如何向 UITextView 的 NSTextAttachment 弹出菜单添加菜单选项?

问题描述 投票:0回答:2

我想在默认图像附件菜单选项中添加另一个菜单选项(复制图像、保存到相机胶卷)。请注意,如果 textView 未处于编辑模式,则当您长按 UITextView 中嵌入的图像时,会显示这些选项。

我尝试向 uimenucontroller 添加自定义菜单并使用 -(void)canPerformAction 来启用或禁用该选项,但这似乎将菜单项添加到 uitextView 的编辑菜单中,并且对附件弹出菜单没有影响。

-(void)canPerformAction 似乎永远不会在长按图像附件时被调用。

uitextview uimenucontroller nstextattachment
2个回答
3
投票

据 Apple 称,没有公共 API 可以执行此操作,但事实证明,用外观和行为相同的菜单替换默认菜单相对简单。

在包含 UITextView 的 viewController 中添加以下或类似内容,并将其设置为 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];

    }];

}

0
投票

iOS 17 在

UITextViewDelegate
上添加了新方法来自定义图像和链接的主要操作和长按上下文菜单。

optional func textView(
    _ textView: UITextView,
    primaryActionFor textItem: UITextItem,
    defaultAction: UIAction
) -> UIAction?

optional func textView(
    _ textView: UITextView,
    menuConfigurationFor textItem: UITextItem,
    defaultMenu: UIMenu
) -> UITextItem.MenuConfiguration?

https://developer.apple.com/documentation/uikit/uitextviewdelegate/4173165-textview

https://developer.apple.com/documentation/uikit/uitextviewdelegate/4173164-textview

© www.soinside.com 2019 - 2024. All rights reserved.