iOS:使用可单击的标签和用户名创建文本区域

iOS:使用可单击的标签和用户名创建文本区域,ios,objective-c,xcode,uilabel,uitextview,Ios,Objective C,Xcode,Uilabel,Uitextview,我试图创建一个包含可点击的hashtags(#abc)和用户名(@xyz)的文本视图。最初,我将UILabel子类化,尽管我已使其正常工作,但只有当文本的范围小于中的102个字符时,该区域才可单击(下面的boundingRectForCharacterRange函数开始返回{0,0}) 接下来,我尝试将UITextView子类化,它将此限制增加到大约300个字符,但仍然存在相同的问题 有人知道我如何提高这个限制吗?我最多使用1000个字符 我的子类UITextView代码如下(我知道我还没有完成

我试图创建一个包含可点击的hashtags(#abc)和用户名(@xyz)的文本视图。最初,我将UILabel子类化,尽管我已使其正常工作,但只有当文本的范围小于中的102个字符时,该区域才可单击(下面的boundingRectForCharacterRange函数开始返回{0,0})

接下来,我尝试将UITextView子类化,它将此限制增加到大约300个字符,但仍然存在相同的问题

有人知道我如何提高这个限制吗?我最多使用1000个字符

我的子类UITextView代码如下(我知道我还没有完成协议部分,但希望您能了解我的问题…):

ClickableTextView.h

#import <UIKit/UIKit.h>

@protocol ClickableTextViewDelegate <NSObject>

@required
- (void)hashTagPressed:(NSString*)hashtagName;
- (void)usernamePressed:(NSString*)username;

@end

@interface ClickableTextView : UITextView
{
    NSMutableArray *hashtags;
    NSMutableArray *usernames;
    UIColor *clickableColor;
    //id <ClickableTextViewDelegate> labelDelegate;
}

//@property (nonatomic,strong) id labelDelegate;

- (void)setClickableColor:(UIColor*)color;

@end
ViewController.m

#import "ClickableTextView.h"

@implementation ClickableTextView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code

        clickableColor = [UIColor blueColor];

        self.userInteractionEnabled = YES;
        self.editable = NO;
        self.scrollEnabled = NO;
        self.textContainerInset = UIEdgeInsetsZero;

        UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(respondToTapGesture:)];

        tapRecognizer.numberOfTapsRequired = 1;
        [self addGestureRecognizer:tapRecognizer];
    }
    return self;
}

- (void)setText:(NSString*)text
{
    [super setText:text];

    NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:text];
    [self setAttributedText:attrString];

    if(!hashtags) {
        hashtags = [NSMutableArray array];
    }

    if(!usernames) {
        usernames = [NSMutableArray array];
    }

    [hashtags removeAllObjects];
    [usernames removeAllObjects];

    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"#(\\w+)" options:0 error:nil];
    NSArray *matches = [regex matchesInString:text options:0 range:NSMakeRange(0, text.length)];
    for(NSTextCheckingResult *match in matches) {
        NSRange tagRange = [match rangeAtIndex:1];
        tagRange.location--;
        tagRange.length++;

        [attrString addAttribute:NSForegroundColorAttributeName value:clickableColor range:tagRange];

        CGRect tagRect = [self boundingRectForCharacterRange:tagRange];
        [hashtags addObject:[NSDictionary dictionaryWithObjects:@[[text substringWithRange:tagRange], [NSNumber numberWithInt:tagRect.origin.x], [NSNumber numberWithInt:tagRect.origin.y], [NSNumber numberWithInt:tagRect.size.width], [NSNumber numberWithInt:tagRect.size.height]] forKeys:@[@"text", @"x", @"y", @"width", @"height"]]];
    }

    regex = [NSRegularExpression regularExpressionWithPattern:@"@(\\w+)" options:0 error:nil];
    matches = [regex matchesInString:text options:0 range:NSMakeRange(0, text.length)];
    for(NSTextCheckingResult *match in matches) {
        NSRange userRange = [match rangeAtIndex:1];
        userRange.location--;
        userRange.length++;

        [attrString addAttribute:NSForegroundColorAttributeName value:clickableColor range:userRange];

        CGRect userRect = [self boundingRectForCharacterRange:userRange];
        [usernames addObject:[NSDictionary dictionaryWithObjects:@[[text substringWithRange:userRange], [NSNumber numberWithInt:userRect.origin.x], [NSNumber numberWithInt:userRect.origin.y], [NSNumber numberWithInt:userRect.size.width], [NSNumber numberWithInt:userRect.size.height]] forKeys:@[@"text", @"x", @"y", @"width", @"height"]]];
    }

    [self setAttributedText:attrString];

    [self sizeToFit];
}

- (CGRect)boundingRectForCharacterRange:(NSRange)range
{
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:[self attributedText]];

    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
    [textStorage addLayoutManager:layoutManager];

    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:[self bounds].size];
    [layoutManager addTextContainer:textContainer];

    NSRange glyphRange;
    [layoutManager characterRangeForGlyphRange:range actualGlyphRange:&glyphRange];

    return [layoutManager boundingRectForGlyphRange:glyphRange inTextContainer:textContainer];
}

- (void)respondToTapGesture:(UITapGestureRecognizer*)recognizer
{
    CGPoint point = [recognizer locationInView:self];

    for(NSDictionary *hashtag in hashtags) {
        CGRect tagRect = CGRectMake([[hashtag objectForKey:@"x"] floatValue], [[hashtag objectForKey:@"y"] floatValue], [[hashtag objectForKey:@"width"] floatValue], [[hashtag objectForKey:@"height"] floatValue]);

        if(CGRectContainsPoint(tagRect, point)) {
            NSLog(@"Hashtag: %@", [hashtag objectForKey:@"text"]);
        }
    }

    for(NSDictionary *username in usernames) {
        CGRect userRect = CGRectMake([[username objectForKey:@"x"] floatValue], [[username objectForKey:@"y"] floatValue], [[username objectForKey:@"width"] floatValue], [[username objectForKey:@"height"] floatValue]);

        if(CGRectContainsPoint(userRect, point)) {
            NSLog(@"Username: %@", [username objectForKey:@"text"]);
        }
    }
}

- (void)setClickableColor:(UIColor*)color
{
    clickableColor = color;

    if(self.text) {
        [self setText:self.text];
    }
}

@end
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    ClickableTextView *textView = [[ClickableTextView alloc] initWithFrame:CGRectMake(50, 100, self.view.frame.size.width - 100, 100)];
    textView.text = @"A #quick test. A quick test. A quick test. A quick test. A quick test. A quick test. A quick test. A quick test. A quick test. A quick test. A #quick test. A quick test. A quick test. A quick test. A quick test. A quick test. A quick test. A quick test. A quick test. A quick test. A quiiiiiiick #test";

    [self.view addSubview:textView];
}

@end

请帮忙

为什么不直接使用
ui按钮
?谢谢你的回复,彼得。文本是动态的,所以我永远不知道可点击的链接会在哪里。如果我这样做的话,我仍然需要得到hashtag/username文本的边界cgrit,这是不起作用的部分。您是否尝试过使用IFTweetLabel..在label@Vidhyanand900,谢谢你的提醒,但我希望能解决我的问题。我想自己做这件事,这样我可以在将来定制它,因为我喜欢从我的错误/缺点中学习:)有什么想法吗?@Damien你解决了吗?关于内容不断变化的文本视图,我也面临着同样的问题。。。我的第一个想法是定义操作键:@、#、删除、返回、纯文本和粘贴操作,将它们放在json中,并存储在一个可变数组中,类型为:hashTag、userName、brakeLine和plainText。通过切换json中的最后一个类型和确定更改类型、追加字符串或删除最后一个json的操作。我还在努力,希望也能听到你的声音:)