Skip to content

Instantly share code, notes, and snippets.

@HamGuy
Created April 17, 2019 10:43
Show Gist options
  • Save HamGuy/8ed1312996601392e50c7e384c70a893 to your computer and use it in GitHub Desktop.
Save HamGuy/8ed1312996601392e50c7e384c70a893 to your computer and use it in GitHub Desktop.
HGLabel
//
// HGLabel.h
//
// Created by HamGuy on 2019/4/17.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class HGLabel;
@protocol HGLabelDelegate <NSObject>
-(void)label:(HGLabel *)label didTapURL:(NSString *)url atRange:(NSRange)range;
@end
/**
可实现链接高亮显示,点击跳转以及长按复制功能的 Label
*/
@interface HGLabel : UILabel
/**
链接颜色
*/
@property (nonatomic, strong) IBInspectable UIColor* linkColor;
/**
是否可长按复制
*/
@property (nonatomic, assign) IBInspectable BOOL longPressAble;
/**
长安时间,默认 1 秒
*/
@property (nonatomic, assign) IBInspectable NSTimeInterval timeToPress;
//@property (nonatomic, readonly ,strong) NSLayoutManager* layoutManager;
//@property (nonatomic, readonly ,strong) NSTextContainer* textContainer;
//@property (nonatomic, readonly ,strong) NSTextStorage* textStorage;
@property (nonatomic, weak) id<CCLabelDelegate> delegate;
/**
添加链接
@param linkText 链接文字
@param urlString 跳转 URL
*/
-(void)addLink:(NSString *)linkText withURL:(NSString *)urlString;
@end
NS_ASSUME_NONNULL_END
//
// HGLabell.m
//
// Created by HamGuy on 2019/4/17.
//
#import "HGLabel.h"
@interface HGLabel ()
@property (nonatomic, strong) NSLayoutManager* layoutManager;
@property (nonatomic, strong) NSTextContainer* textContainer;
@property (nonatomic, strong) NSTextStorage* textStorage;
@property (nonatomic, strong) NSMutableDictionary* linkInfo;
@end
@implementation HGLabel
@synthesize attributedText = _attributedText;
@synthesize numberOfLines = _numberOfLines;
@synthesize lineBreakMode = _lineBreakMode;
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
[self setup];
}
return self;
}
#pragma mark Override
- (void)drawTextInRect:(CGRect)rect {
// [super drawTextInRect:rect];
NSRange range = [self.layoutManager glyphRangeForTextContainer:self.textContainer];
// CGRect tmpRect = [self.layoutManager boundingRectForGlyphRange:range inTextContainer:self.textContainer];
// CGFloat offsetY = (self.bounds.size.height - tmpRect.size.height) ;
// CGPoint offset = CGPointMake(0, offsetY);
[self.layoutManager drawBackgroundForGlyphRange:range atPoint:CGPointZero];
[self.layoutManager drawGlyphsForGlyphRange:range atPoint:CGPointZero];
}
-(void)setTextStorage:(NSTextStorage *)textStorage {
_textStorage = textStorage;
[self.textStorage addLayoutManager:self.layoutManager];
}
-(NSAttributedString *)attributedText {
return _attributedText;
}
- (void)setAttributedText:(NSAttributedString *)attributedText {
_attributedText = attributedText;
if(!attributedText) {
// self.textStorage = [[NSTextStorage alloc] init];
self.linkInfo = [@{} mutableCopy];
} else {
self.textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedText];
[self.textStorage setAttributedString:attributedText];
}
[self setNeedsDisplay];
}
-(NSInteger)numberOfLines {
return _numberOfLines;
}
- (void)setNumberOfLines:(NSInteger)numberOfLines {
_numberOfLines = numberOfLines;
self.textContainer.maximumNumberOfLines = numberOfLines;
}
- (NSLineBreakMode)lineBreakMode {
return _lineBreakMode;
}
- (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode {
_lineBreakMode = lineBreakMode;
self.textContainer.lineBreakMode = lineBreakMode;
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
return self.longPressAble && action == @selector(copyText);
}
- (void)layoutSubviews {
[super layoutSubviews];
self.textContainer.size = self.bounds.size;
}
//- (CGRect)boundingRectWithSize:(CGSize)size
//{
// self.textContainer.size = size;
//
// NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer];
//
// CGRect boundingRect = [self.layoutManager boundingRectForGlyphRange:glyphRange
// inTextContainer:self.textContainer];
// boundingRect.origin.x = 0;
// boundingRect.origin.y = 0;
//
// return boundingRect;
//}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = touches.anyObject;
CGPoint locationOfTouch = [touch locationInView:self];
_textContainer.size = self.bounds.size;
NSUInteger indexOfCharacter = [_layoutManager glyphIndexForPoint:locationOfTouch inTextContainer:_textContainer];
__weak typeof(self) weakSelf = self;
[_linkInfo enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSValue* obj, BOOL * _Nonnull stop) {
NSRange range = obj.rangeValue;
if (NSLocationInRange(indexOfCharacter, range) && [weakSelf.delegate respondsToSelector:@selector(label:didTapURL:atRange:)]) {
[weakSelf.delegate label:weakSelf didTapURL:key atRange:range];
}
}];
}
#pragma mark Public
- (void)addLink:(NSString *)linkText withURL:(NSString *)urlString {
NSString *text = self.attributedText.string;
if(!text) {
return;
}
NSRange range = [text rangeOfString:linkText];
if(range.location != NSNotFound) {
self.linkInfo[urlString] = [NSValue valueWithRange:range];
}
}
#pragma mark Private
-(void)setup {
self.timeToPress = 1;
self.userInteractionEnabled = YES;
UILongPressGestureRecognizer *gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
gesture.minimumPressDuration = _timeToPress;
[self addGestureRecognizer:gesture];
self.linkInfo = [@{} mutableCopy];
self.layoutManager = [NSLayoutManager new];
self.textContainer = [[NSTextContainer alloc] initWithSize:CGSizeZero];
[self.layoutManager addTextContainer:self.textContainer];
self.textContainer.lineFragmentPadding = 0;
self.textContainer.maximumNumberOfLines = 0;
self.textContainer.lineBreakMode = self.lineBreakMode;
}
- (void)longPress:(UIGestureRecognizer *)gesture {
UIMenuItem *item = [[UIMenuItem alloc] initWithTitle:@"复制" action:@selector(copyText)];
UIMenuController *menuController = [UIMenuController sharedMenuController];
menuController.menuItems = @[item];
[menuController setTargetRect:self.frame inView:self];
[menuController setMenuVisible:YES animated:YES];
}
-(void)copyText {
NSString *text = self.attributedText.string;
if(!text) {
self.text = text;
}
[UIPasteboard generalPasteboard].string = text;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment