Skip to content

Commit

Permalink
Merge branch 'molon'
Browse files Browse the repository at this point in the history
  • Loading branch information
molon committed Sep 22, 2015
2 parents 95a4df9 + 152b76b commit b033d01
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 53 deletions.
6 changes: 4 additions & 2 deletions Classes/MLExpressionManager.m
Expand Up @@ -163,9 +163,11 @@ + (NSAttributedString*)expressionAttributedStringWithString:(id)string expressio
if (imageName.length>0) {
//加个表情到结果中
NSString *imagePath = [expression.bundleName stringByAppendingPathComponent:imageName];
UIImage *image = [UIImage imageNamed:imagePath];

MLTextAttachment *textAttachment = [MLTextAttachment textAttachmentWithLineHeightMultiple:kExpressionLineHeightMultiple imageBlock:^UIImage *(CGRect imageBounds, NSTextContainer *textContainer, NSUInteger charIndex, MLTextAttachment *textAttachment) {
return [UIImage imageNamed:imagePath];
}];
return image;
} imageAspectRatio:image.size.width/image.size.height];
[resultAttributedString appendAttributedString:[NSAttributedString attributedStringWithAttachment:textAttachment]];
}else{
//找不到对应图像名称就直接加上去
Expand Down
32 changes: 21 additions & 11 deletions Classes/MLLabel.m
Expand Up @@ -147,6 +147,7 @@ - (MLLabelLayoutManager *)layoutManager
{
if (!_layoutManager) {
_layoutManager = [MLLabelLayoutManager new];
_layoutManager.allowsNonContiguousLayout = NO;
_layoutManager.delegate = self;
}
return _layoutManager;
Expand Down Expand Up @@ -208,8 +209,8 @@ - (void)setAttributedText:(NSAttributedString *)attributedText
- (CGSize)textContainerSizeWithBoundsSize:(CGSize)size
{
//bounds改了之后,要相应的改变textContainer的size,但是要根据insets调整
CGFloat width = MAX(0, size.width-_textInsets.left-_textInsets.right);
CGFloat height = MAX(0, size.height-_textInsets.top-_textInsets.bottom);
CGFloat width = fmax(0, size.width-_textInsets.left-_textInsets.right);
CGFloat height = fmax(0, size.height-_textInsets.top-_textInsets.bottom);
return CGSizeMake(width, height);
}

Expand Down Expand Up @@ -306,10 +307,17 @@ - (NSDictionary *)attributesFromLabelProperties

- (CGRect)textRectForBounds:(CGRect)bounds attributedString:(NSAttributedString*)attributedString limitedToNumberOfLines:(NSInteger)numberOfLines lineCount:(NSInteger*)lineCount
{
//这种算是特殊情况,如果为空字符串,那就没必要必要了,也忽略textInset,这样比较合理
if (attributedString.length<=0) {
bounds.size = CGSizeZero;
return bounds;
}

CGSize newTextContainerSize = [self textContainerSizeWithBoundsSize:bounds.size];
if (newTextContainerSize.width<=0||newTextContainerSize.height<=0){
CGRect textBounds = CGRectZero;
textBounds.size = CGSizeMake(_textInsets.left+_textInsets.right, _textInsets.top+_textInsets.bottom);
textBounds.origin = bounds.origin;
textBounds.size = CGSizeMake(fmin(_textInsets.left+_textInsets.right,CGRectGetWidth(bounds)), fmin(_textInsets.top+_textInsets.bottom,CGRectGetHeight(bounds)));
return textBounds;
}

Expand All @@ -321,11 +329,13 @@ - (CGRect)textRectForBounds:(CGRect)bounds attributedString:(NSAttributedString*
textContainer.maximumNumberOfLines = numberOfLines;
textContainer.lineBreakMode = _textContainer.lineBreakMode;
textContainer.lineFragmentPadding = _textContainer.lineFragmentPadding;

MLLabelLayoutManager *layoutManager = [[MLLabelLayoutManager alloc]init];
layoutManager.delegate = self;
[textStorage addLayoutManager:layoutManager];
[layoutManager addTextContainer:textContainer];

[textStorage addLayoutManager:layoutManager];

NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];

if (lineCount) {
Expand All @@ -340,11 +350,11 @@ - (CGRect)textRectForBounds:(CGRect)bounds attributedString:(NSAttributedString*
//执行这个之前必须执行glyphRangeForTextContainer
CGRect textBounds = [layoutManager usedRectForTextContainer:textContainer];

textBounds.size.width = MIN(ceilf(textBounds.size.width), newTextContainerSize.width);
textBounds.size.height = MIN(ceilf(textBounds.size.height), newTextContainerSize.height);
textBounds.size.width = fmin(ceilf(textBounds.size.width), newTextContainerSize.width);
textBounds.size.height = fmin(ceilf(textBounds.size.height), newTextContainerSize.height);
textBounds.origin = bounds.origin;

textBounds.size = CGSizeMake(CGRectGetWidth(textBounds)+_textInsets.left+_textInsets.right, CGRectGetHeight(textBounds)+_textInsets.top+_textInsets.bottom);
textBounds.size = CGSizeMake(fmin(CGRectGetWidth(textBounds)+_textInsets.left+_textInsets.right,CGRectGetWidth(bounds)), fmin(CGRectGetHeight(textBounds)+_textInsets.top+_textInsets.bottom,CGRectGetHeight(bounds)));

// NSLog(@"bounds:%@ result:%@ %p",NSStringFromCGRect(bounds),NSStringFromCGRect(textBounds),self);
return textBounds;
Expand All @@ -359,7 +369,7 @@ - (BOOL)adjustsCurrentFontSizeToFitWidthWithScaleFactor:(CGFloat)scaleFactor num
mustReturnYES = YES;
}
//总得有个极限
scaleFactor = MAX(scaleFactor, ADJUST_MIN_SCALE_FACTOR);
scaleFactor = fmax(scaleFactor, ADJUST_MIN_SCALE_FACTOR);

//遍历并且设置一个新的字体
NSMutableAttributedString *attrStr = [originalAttributedText mutableCopy];
Expand Down Expand Up @@ -444,7 +454,7 @@ - (void)drawTextInRect:(CGRect)rect
}

CGFloat textWidth = [self textRectForBounds:CGRectMake(0, 0, MLFLOAT_MAX, MLFLOAT_MAX) attributedString:attributedString limitedToNumberOfLines:0 lineCount:NULL].size.width;
textWidth = MAX(0, textWidth-_textInsets.left-_textInsets.right);
textWidth = fmax(0, textWidth-_textInsets.left-_textInsets.right);
if (textWidth>0) {
CGFloat availableWidth = _textContainer.size.width*self.numberOfLines;
if (textWidth > availableWidth) {
Expand Down Expand Up @@ -515,7 +525,7 @@ - (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)num
}

CGFloat textWidth = [self textRectForBounds:CGRectMake(0, 0, MLFLOAT_MAX, MLFLOAT_MAX) attributedString:attributedString limitedToNumberOfLines:0 lineCount:NULL].size.width;
textWidth = MAX(0, textWidth-_textInsets.left-_textInsets.right);
textWidth = fmax(0, textWidth-_textInsets.left-_textInsets.right);
if (textWidth>0) {
CGFloat availableWidth = _textContainer.size.width*numberOfLines;
if (textWidth > availableWidth) {
Expand Down Expand Up @@ -557,7 +567,7 @@ - (CGSize)intrinsicContentSize {
- (CGSize)preferredSizeWithMaxWidth:(CGFloat)maxWidth
{
CGSize size = [self sizeThatFits:CGSizeMake(maxWidth, MLFLOAT_MAX)];
size.width = MIN(size.width, maxWidth); //在numberOfLine为1模式下返回的可能会比maxWidth大,所以这里我们限制下
size.width = fmin(size.width, maxWidth); //在numberOfLine为1模式下返回的可能会比maxWidth大,所以这里我们限制下
return size;
}

Expand Down
13 changes: 10 additions & 3 deletions Classes/MLLinkLabel.h
Expand Up @@ -29,8 +29,8 @@ typedef NS_OPTIONS(NSUInteger, MLDataDetectorTypes) {

typedef NS_ENUM(NSUInteger, MLLinkType) {
MLLinkTypeNone = 0,
MLLinkTypeURL = 1, // 电话
MLLinkTypePhoneNumber = 2, // 链接
MLLinkTypeURL = 1, // 链接
MLLinkTypePhoneNumber = 2, // 电话
MLLinkTypeEmail = 3, // 邮箱
MLLinkTypeUserHandle = 4, //@
MLLinkTypeHashtag = 5, //#..#
Expand All @@ -46,6 +46,9 @@ typedef NS_ENUM(NSUInteger, MLLinkType) {
@protocol MLLinkLabelDelegate <NSObject>

- (void)didClickLink:(MLLink*)link linkText:(NSString*)linkText linkLabel:(MLLinkLabel*)linkLabel;

@optional

- (void)didLongPressLink:(MLLink*)link linkText:(NSString*)linkText linkLabel:(MLLinkLabel*)linkLabel;

@end
Expand All @@ -65,7 +68,7 @@ typedef NS_ENUM(NSUInteger, MLLinkType) {
//默认为0.3秒
@property (nonatomic, assign) NSTimeInterval activeLinkToNilDelay;

//是否允许在link内line break,默认为NO,即为不允许,这样的话链接会尽量的不换行
//是否允许在link内line break,默认为YES,即为允许,这样的话链接会能折行就折行和正常文本一样
@property (nonatomic, assign) BOOL allowLineBreakInsideLinks;

//优先级比delegate高
Expand All @@ -92,6 +95,10 @@ typedef NS_ENUM(NSUInteger, MLLinkType) {
* 设置文本后添加link,注意如果在此之后设置了text、attributedText、dataDetectorTypes或dataDetectorTypesOfAttributedLinkValue属性的话添加的link会丢失。
*/
- (MLLink*)addLinkWithType:(MLLinkType)type value:(NSString*)value range:(NSRange)range;
/**
* 设置文本后添加link,注意如果在此之后设置了text、attributedText、dataDetectorTypes或dataDetectorTypesOfAttributedLinkValue属性的话添加的link会丢失。
*/
- (NSArray*)addLinks:(NSArray*)links;

//下面俩是为了编写代码时候外部设置block时候不需要自定义名字了,方便。
- (void)setDidClickLinkBlock:(void (^)(MLLink *link, NSString *linkText, MLLinkLabel *label))didClickLinkBlock;
Expand Down
61 changes: 36 additions & 25 deletions Classes/MLLinkLabel.m
Expand Up @@ -158,9 +158,9 @@ - (void)commonInit
self.activeLinkToNilDelay = 0.3f;

//默认除了话题和@都检测
self.dataDetectorTypes = MLDataDetectorTypeURL|MLDataDetectorTypePhoneNumber|MLDataDetectorTypeEmail|MLDataDetectorTypeAttributedLink;
self.dataDetectorTypesOfAttributedLinkValue = MLDataDetectorTypeNone;
self.allowLineBreakInsideLinks = NO;
_dataDetectorTypes = MLDataDetectorTypeURL|MLDataDetectorTypePhoneNumber|MLDataDetectorTypeEmail|MLDataDetectorTypeAttributedLink;
_dataDetectorTypesOfAttributedLinkValue = MLDataDetectorTypeNone;
_allowLineBreakInsideLinks = YES;

[self addGestureRecognizer:self.longPressGestureRecognizer];
}
Expand Down Expand Up @@ -461,27 +461,7 @@ - (void)longPressGestureDidFire:(UILongPressGestureRecognizer *)sender {
#pragma mark - 外部调用相关
- (BOOL)addLink:(MLLink*)link
{
if (!link||NSMaxRange(link.linkRange)>self.textStorage.length) {
return FALSE;
}

//检测是否此位置已经有东西占用
for (MLLink *aLink in self.links){
if (NSMaxRange(NSIntersectionRange(aLink.linkRange, link.linkRange))>0){
return FALSE;
}
}

if (self.beforeAddLinkBlock) {
self.beforeAddLinkBlock(link);
}

//加入它
[self.links addObject:link];
//重绘
[self reSetText];

return YES;
return [self addLinks:@[link]].count>0;
}

- (MLLink*)addLinkWithType:(MLLinkType)type value:(NSString*)value range:(NSRange)range
Expand All @@ -490,6 +470,37 @@ - (MLLink*)addLinkWithType:(MLLinkType)type value:(NSString*)value range:(NSRang
return [self addLink:link]?link:nil;
}

- (NSArray*)addLinks:(NSArray*)links
{
NSMutableArray *validLinks = [NSMutableArray arrayWithCapacity:links.count];
for (MLLink *link in links) {
if (!link||NSMaxRange(link.linkRange)>self.textStorage.length) {
continue;
}

//检测是否此位置已经有东西占用
for (MLLink *aLink in self.links){
if (NSMaxRange(NSIntersectionRange(aLink.linkRange, link.linkRange))>0){
continue;
}
}

if (self.beforeAddLinkBlock) {
self.beforeAddLinkBlock(link);
}

//加入它
[self.links addObject:link];

[validLinks addObject:link];
}

//重绘
[self reSetText];

return validLinks;
}

- (void)invalidateDisplayForLinks
{
[self reSetText];
Expand All @@ -506,7 +517,7 @@ -(BOOL)layoutManager:(NSLayoutManager *)layoutManager shouldBreakLineByWordBefor
return YES;
}

//让在链接区间下,尽量不beak
//让在链接区间下,尽量不break
for (MLLink *link in self.links) {
if (NSLocationInRange(charIndex,link.linkRange)) {
return NO;
Expand Down
11 changes: 8 additions & 3 deletions Classes/MLTextAttachment.h
Expand Up @@ -15,13 +15,18 @@

/**
* 优先级比上面的高,以lineHeight为根据来决定高度
* 1.如果有提供imageBlock,并且其支持imageBounds为CGRectZero下返回图像的话,宽度会根据图像比例自适应
* 2.如果没提供imageBlock或者其返回image为nil,会设置宽度和高度相等
* 宽度根据imageAspectRatio来定
*/
@property (readonly, nonatomic, assign) CGFloat lineHeightMultiple;

/**
* image.size.width/image.size.height
*/
@property (readonly, nonatomic, assign) CGFloat imageAspectRatio;

+ (instancetype)textAttachmentWithWidth:(CGFloat)width height:(CGFloat)height imageBlock:(UIImage * (^)(CGRect imageBounds,NSTextContainer *textContainer,NSUInteger charIndex,MLTextAttachment *textAttachment))imageBlock;

+ (instancetype)textAttachmentWithLineHeightMultiple:(CGFloat)lineHeightMultiple imageBlock:(UIImage * (^)(CGRect imageBounds,NSTextContainer *textContainer,NSUInteger charIndex,MLTextAttachment *textAttachment))imageBlock;
+ (instancetype)textAttachmentWithLineHeightMultiple:(CGFloat)lineHeightMultiple imageBlock:(UIImage * (^)(CGRect imageBounds,NSTextContainer *textContainer,NSUInteger charIndex,MLTextAttachment *textAttachment))imageBlock
imageAspectRatio:(CGFloat)imageAspectRatio;

@end
10 changes: 5 additions & 5 deletions Classes/MLTextAttachment.m
Expand Up @@ -14,6 +14,7 @@ @interface MLTextAttachment()
@property (nonatomic, assign) CGFloat height;

@property (nonatomic, assign) CGFloat lineHeightMultiple;
@property (nonatomic, assign) CGFloat imageAspectRatio;

@property (nonatomic, copy) UIImage * (^imageBlock)(CGRect imageBounds,NSTextContainer *textContainer,NSUInteger charIndex,MLTextAttachment *textAttachment);

Expand All @@ -31,10 +32,12 @@ + (instancetype)textAttachmentWithWidth:(CGFloat)width height:(CGFloat)height im
}

+ (instancetype)textAttachmentWithLineHeightMultiple:(CGFloat)lineHeightMultiple imageBlock:(UIImage * (^)(CGRect imageBounds,NSTextContainer *textContainer,NSUInteger charIndex,MLTextAttachment *textAttachment))imageBlock
imageAspectRatio:(CGFloat)imageAspectRatio
{
MLTextAttachment *textAttachment = [MLTextAttachment new];
textAttachment.lineHeightMultiple = lineHeightMultiple;
textAttachment.imageBlock = imageBlock;
textAttachment.imageAspectRatio = imageAspectRatio;
return textAttachment;
}

Expand Down Expand Up @@ -65,11 +68,8 @@ - (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer prop

if (self.lineHeightMultiple>0) {
width = height = baseLineHeight*self.lineHeightMultiple;
if (self.imageBlock) {
UIImage *image = self.imageBlock(CGRectZero,textContainer,charIndex,self);
if (image) {
width = height*(image.size.width/image.size.height);
}
if (self.imageAspectRatio>0) {
width = height*self.imageAspectRatio;
}
}else{
if (width==0&&height==0) {
Expand Down
21 changes: 20 additions & 1 deletion Example/MLLabel/ViewControllers/ListNoNibViewController.m
Expand Up @@ -17,6 +17,7 @@
@interface ListNoNibViewController ()

@property (nonatomic, strong) NSArray *expressionData;
@property (nonatomic, strong) NSMutableDictionary *cellHeights;

@end

Expand All @@ -41,11 +42,20 @@ - (void)didReceiveMemoryWarning {
// Dispose of any resources that can be recreated.
}

#pragma mark - getter
- (NSMutableDictionary *)cellHeights
{
if (!_cellHeights) {
_cellHeights = [NSMutableDictionary new];
}
return _cellHeights;
}

#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 30;
return 15;
}


Expand All @@ -59,7 +69,16 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
return cell;
}


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.cellHeights[indexPath]) {
self.cellHeights[indexPath] = @([self heightForRowAtIndexPath:indexPath tableView:tableView]);
}
return [self.cellHeights[indexPath] floatValue];
}

- (CGFloat)heightForRowAtIndexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableView
{
CGFloat height = [ListNoNibTableViewCell heightForExpressionText:self.expressionData[indexPath.row%self.expressionData.count] width:self.view.frameWidth];
return height;
Expand Down

0 comments on commit b033d01

Please sign in to comment.