如何获得“取消选择” UILabel 上的通知

发布于 2024-09-26 08:04:51 字数 2361 浏览 2 评论 0原文

我有 UILabel,我需要它能够支持复制和粘贴(实际上只能复制,因为它是只读的)。我对 UILabel 进行了子类化以支持复制,并且它工作正常。我还添加了文本突出显示,以便用户在单击标签时知道他到底复制了什么。

我的问题是,当用户单击其他地方时,我不知道如何取消该突出显示。复制气泡消失,但我没有收到任何回调,因此文本保持突出显示。是否有我错过的特殊回调可以使用,或者我是否必须想出一些肮脏的技巧?或者是否有更标准的方法来突出显示 UILabel 中的文本,我不知道它会像复制气泡一样自动处理?

这是我的自定义 UILabel 代码:

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    if(action == @selector(copy:)) {
        return YES;
    }
    else {
        return [super canPerformAction:action withSender:sender];
    }
}

- (BOOL)becomeFirstResponder {
    if([super becomeFirstResponder]) {
        self.highlighted = YES; 

        UIMenuController *menu = [UIMenuController sharedMenuController];
        [menu setTargetRect:self.bounds inView:self];
        [menu setMenuVisible:YES animated:YES];

        return YES;
    }
    return NO;
}

- (BOOL)resignFirstResponder {
    if([super resignFirstResponder]) {
        self.highlighted = NO;

        UIMenuController *menu = [UIMenuController sharedMenuController];
        [menu setMenuVisible:NO animated:YES];
        [menu update];

        return true;
    }
    return false;
}

- (void)copy:(id)sender {
    UIPasteboard *board = [UIPasteboard generalPasteboard];
    [board setString:self.text];
    self.highlighted = NO;
    [self resignFirstResponder];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if([self isFirstResponder]) {
        //UIMenuController *menu = [UIMenuController sharedMenuController];
        //[menu setMenuVisible:NO animated:YES];
        //[menu update];
        [self resignFirstResponder];
    }
    else if([self becomeFirstResponder]) {
        //UIMenuController *menu = [UIMenuController sharedMenuController];
        //[menu setTargetRect:self.bounds inView:self];
        //[menu setMenuVisible:YES animated:YES];
    }
}

- (void)setHighlighted:(BOOL)hl {
    [super setHighlighted:hl];

    [self setNeedsLayout];
}

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    if(self.highlighted) {
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        CGContextSetRGBFillColor(ctx, 0.3, 0.8, 1.0, 0.3);
        CGContextAddRect(ctx, CGRectMake(0, 0, [self textRectForBounds:self.frame limitedToNumberOfLines:1].size.width, self.frame.size.height));
        CGContextFillPath(ctx);
    }
}

任何帮助表示赞赏!

I have UILabel and I need it to be able support copy&paste (actually only copy as it is read only). I subclassed UILabel to support copy and it works fine. I also added text highlight so user knows what exactly is he copying when he clicks on label.

My problem is that I don't know how to cancel that highlight when user clicks somewhere else. Copy bubble disappears, but I don't get any callback so text remains highlighted. Is there special callback I missed that I can use or do I have to come up with some dirty hack? Or is there perhaps more standard way of highlighting text in UILabel that I am not aware of that would be handled automatically like Copy bubble?

Here my custom UILabel code:

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    if(action == @selector(copy:)) {
        return YES;
    }
    else {
        return [super canPerformAction:action withSender:sender];
    }
}

- (BOOL)becomeFirstResponder {
    if([super becomeFirstResponder]) {
        self.highlighted = YES; 

        UIMenuController *menu = [UIMenuController sharedMenuController];
        [menu setTargetRect:self.bounds inView:self];
        [menu setMenuVisible:YES animated:YES];

        return YES;
    }
    return NO;
}

- (BOOL)resignFirstResponder {
    if([super resignFirstResponder]) {
        self.highlighted = NO;

        UIMenuController *menu = [UIMenuController sharedMenuController];
        [menu setMenuVisible:NO animated:YES];
        [menu update];

        return true;
    }
    return false;
}

- (void)copy:(id)sender {
    UIPasteboard *board = [UIPasteboard generalPasteboard];
    [board setString:self.text];
    self.highlighted = NO;
    [self resignFirstResponder];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if([self isFirstResponder]) {
        //UIMenuController *menu = [UIMenuController sharedMenuController];
        //[menu setMenuVisible:NO animated:YES];
        //[menu update];
        [self resignFirstResponder];
    }
    else if([self becomeFirstResponder]) {
        //UIMenuController *menu = [UIMenuController sharedMenuController];
        //[menu setTargetRect:self.bounds inView:self];
        //[menu setMenuVisible:YES animated:YES];
    }
}

- (void)setHighlighted:(BOOL)hl {
    [super setHighlighted:hl];

    [self setNeedsLayout];
}

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    if(self.highlighted) {
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        CGContextSetRGBFillColor(ctx, 0.3, 0.8, 1.0, 0.3);
        CGContextAddRect(ctx, CGRectMake(0, 0, [self textRectForBounds:self.frame limitedToNumberOfLines:1].size.width, self.frame.size.height));
        CGContextFillPath(ctx);
    }
}

Any help appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

甜味拾荒者 2024-10-03 08:04:51

就我个人而言,我会使用 UITextView 并将可编辑选项设置为“否”。

否则,如果您想要更多控制,请对 UILabel 所属的最顶层全屏视图(或窗口)进行子类化。

覆盖 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;

如果命中视图不是您的 UILabel,则创建一个您在 UILabel 子类中处理的 NSNotification,然后取消选择。

顺便说一句,你也应该始终处理touchesCanceled!

Personally i would use a UITextView with option of editable set to NO.

otherwise, if you want more control, subclass your topmost fullscreen view (or window) that your UILabel is a child of.

override - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;

and if the hit view is not your UILabel, then create a NSNotification which you handle in your UILabel subclass, and do the deselect.

BTW, You should ALWAYS handle touchesCanceled also!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文