Skip to content

Instantly share code, notes, and snippets.

@alonecuzzo
Created May 3, 2013 20:07
Show Gist options
  • Save alonecuzzo/5513543 to your computer and use it in GitHub Desktop.
Save alonecuzzo/5513543 to your computer and use it in GitHub Desktop.
//
// LORichTextLabel.m
// RichTextLabel
//
// Created by Locassa on 19/06/2011.
// Copyright 2011 Locassa Ltd. All rights reserved.
//
#import "LORichTextLabel.h"
#import "UIView+Layout.h"
#import "LORichAdditionalTextLabel.h"
@implementation LORichTextLabel {
NSMutableArray *additionalHastagElements;
int additionalTextCounter;
int runningAdditionalTextCounter;
BOOL isBuildingLongHashtag;
}
- (id)initWithWidth:(CGFloat)aWidth {
self = [super initWithFrame:CGRectMake(0.0, 0.0, aWidth, 0.0)];
if(self != nil) {
highlightStyles = [[NSMutableDictionary alloc] init];
elements = [[NSMutableArray alloc] init];
additionalTextCounter = 0;
runningAdditionalTextCounter = 1;
isBuildingLongHashtag = NO;
font = [UIFont fontWithName:@"HelveticaNeue" size:15.0];
textColor = [UIColor blackColor];
}
return self;
}
#pragma mark -
#pragma mark Mutators
- (void)addStyle:(LORichTextLabelStyle *)aStyle forPrefix:(NSString *)aPrefix {
if((aPrefix == nil) || (aPrefix.length == 0)) {
[NSException raise:NSInternalInconsistencyException
format:@"Prefix must be specified in %@", NSStringFromSelector(_cmd)];
}
[highlightStyles setObject:aStyle forKey:aPrefix];
}
- (void)setFont:(UIFont *)value {
if([font isEqual:value]) {
return;
}
font = value;
[self setNeedsDisplay];
}
- (void)setTextColor:(UIColor *)value {
if([textColor isEqual:value]) {
return;
}
textColor = value;
[self setNeedsLayout];
}
//- (void)addTextToAdditionalCopyArray:(NSString *)elementString pString:(NSString *)parentString {
// additionalTextCounter++;
// LORichAdditionalTextLabel *additionalTextLabel = [[LORichAdditionalTextLabel alloc] init];
// additionalTextLabel.text = elementString;
// additionalTextLabel.parentText = parentString;
// additionalTextLabel.textId = additionalTextCounter;
// [additionalHastagElements addObject:additionalTextLabel];
//}
//- (BOOL)stringExistsInAdditionalCopyArray:(NSString *)element {
// for (LORichAdditionalTextLabel *label in additionalHastagElements) {
// if ([label.text isEqualToString:element]) {
// return YES;
// }
// }
// return NO;
//}
-(void)fixAdditionalTextCarriageReturns:(LORichAdditionalTextLabel *)element hot:(BOOL)isHot {
//do what we were doing before
if ([element.text rangeOfString:@"\n"].location != NSNotFound)
{
NSArray *temp = [element.text componentsSeparatedByString:@"\n"];
for (NSString *tempEl in temp)
{
if([tempEl length] == 0){
LORichAdditionalTextLabel *tempAdditionalText = [[LORichAdditionalTextLabel alloc] init];
tempAdditionalText.text = @"\n";
tempAdditionalText.parentText = element.parentText;
tempAdditionalText.isHot = isHot;
[elements addObject:tempAdditionalText];
} else {
LORichAdditionalTextLabel *tempAdditionalText = [[LORichAdditionalTextLabel alloc] init];
tempAdditionalText.text = tempEl;
tempAdditionalText.parentText = element.parentText;
tempAdditionalText.isHot = isHot;
[elements addObject:tempAdditionalText];
}
}
}
else
{
if(element.text.length > 0){
LORichAdditionalTextLabel *tempAdditionalText = [[LORichAdditionalTextLabel alloc] init];
tempAdditionalText.text = element;
tempAdditionalText.parentText = element.parentText;
tempAdditionalText.isHot = isHot;
[elements addObject:element];
}
}
}
//-(void)fixCarriageReturns:(NSString *)element {
// //do what we were doing before
// if ([element rangeOfString:@"\n"].location != NSNotFound)
// {
// NSArray *temp = [element componentsSeparatedByString:@"\n"];
// for (NSString *tempEl in temp)
// {
// if([tempEl length] == 0){
// [elements addObject:@"\n"];
// } else {
// [elements addObject:tempEl];
// }
// }
// }
// else
// {
// if(element.length > 0){
// [elements addObject:element];
// }
// }
//}
- (void)setText:(NSString *)value {
int maxStringLength = 24;
elements = nil;
elements = [NSMutableArray array];
for (NSString *element in [value componentsSeparatedByString:@" "])
{
if ([element length] > maxStringLength) {
for(NSString *prefix in [highlightStyles allKeys]) {
//need to check and see if the element is in our fancy array
if([element hasPrefix:prefix]) {
//how many substrings is it going to have?
//once we find the number, pop the strings into the 'hastagarray' or something and then decrement the substring counter
//after each iteration
isBuildingLongHashtag = YES;
break;
} else {
isBuildingLongHashtag = NO;
}
}
if(!additionalHastagElements) {
additionalHastagElements = [[NSMutableArray alloc] init];
}
NSMutableArray *tmpCharArray = [[NSMutableArray alloc] initWithCapacity:maxStringLength];
//we're going to need to break this up so create one of the additional labels
for (int i = 0; i < [element length]; i++) {
char c = [element characterAtIndex:i];
const unichar ca[] = {c};
[tmpCharArray addObject:[NSString stringWithCharacters:ca length:sizeof ca / sizeof ca]];
if (i > 0 && i % maxStringLength == 0) {
NSString *reformattedElement = [tmpCharArray componentsJoinedByString:@""];
LORichAdditionalTextLabel *adText = [[LORichAdditionalTextLabel alloc] init];
adText.text = reformattedElement;
adText.parentText = element;
[self fixAdditionalTextCarriageReturns:adText hot:isBuildingLongHashtag];
tmpCharArray = nil;
tmpCharArray = [[NSMutableArray alloc] initWithCapacity:maxStringLength];
}
}
if ([tmpCharArray count] > 0) {
LORichAdditionalTextLabel *adText = [[LORichAdditionalTextLabel alloc] init];
adText.text = [tmpCharArray componentsJoinedByString:@""];
adText.parentText = element;
[self fixAdditionalTextCarriageReturns:adText hot:isBuildingLongHashtag];
}
tmpCharArray = nil;
} else {
LORichAdditionalTextLabel *adText = [[LORichAdditionalTextLabel alloc] init];
adText.text = element;
adText.parentText = element;
[self fixAdditionalTextCarriageReturns:adText hot:NO];
}
}
// NSLog(@"elements: %@", elements);
// NSLog(@"additional elements: %@", additionalHastagElements);
[self setNeedsLayout];
}
//-(BOOL)elementShouldBeTagged:(NSString *)element {
// for (LORichAdditionalTextLabel *additionalElement in additionalHastagElements) {
// if([additionalElement.text isEqualToString:element] && runningAdditionalTextCounter == additionalElement.textId) {
// runningAdditionalTextCounter++;
// return YES;
// }
// }
// return NO;
//}
#pragma mark -
#pragma mark Drawing Methods
- (void)layoutSubviews {
[self removeSubviews];
NSUInteger maxHeight = 999999;
CGPoint position = CGPointZero;
CGSize measureSize = CGSizeMake(self.size.width, maxHeight);
float lineHeight = -1.0f;
// for(NSString *element in elements) {
for(LORichAdditionalTextLabel *element in elements) {
LORichTextLabelStyle *style = nil;
// Find suitable style
for(NSString *prefix in [highlightStyles allKeys]) {
//need to check and see if the element is in our fancy array
if([element.text hasPrefix:prefix] || element.isHot == YES) {
style = [highlightStyles objectForKey:prefix];
break;
}
}
UIFont *styleFont = style.font == nil ? font : style.font;
UIColor *styleColor = style.color == nil ? textColor : style.color;
// Get size of content (check current line before starting new one)
CGSize remainingSize = CGSizeMake(measureSize.width - position.x, maxHeight);
CGSize singleLineSize = CGSizeMake(remainingSize.width, 0.0);
CGSize controlSize = [element.text sizeWithFont:styleFont constrainedToSize:singleLineSize lineBreakMode:UILineBreakModeTailTruncation];
CGSize elementSize = [element.text sizeWithFont:styleFont constrainedToSize:remainingSize];
// stores the line height as measured from the element size; the line size here was never incrementing because the control size height was 0
// so the lines would all overlap
if (lineHeight < 0 && elementSize.height > 0.0f) {
lineHeight = elementSize.height;
}
if(elementSize.height > controlSize.height || elementSize.width == 0) {
position.y += lineHeight;
position.x = 0.0;
}
else if (remainingSize.width <= 0)
{
position.y += [@"LOR ftl" sizeWithFont:styleFont].height;
position.x = 0.0;
}
elementSize = [element.text sizeWithFont:styleFont constrainedToSize:measureSize];
CGRect elementFrame = CGRectMake(position.x, position.y, elementSize.width, elementSize.height);
// Add button or label depending on whether we have a target
if(style.target != nil) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:style.target action:style.action forControlEvents:UIControlEventTouchUpInside];
[button setTitle:element.parentText forState:UIControlStateNormal];
[button setTitleColor:styleColor forState:UIControlStateNormal];
[button setFrame:elementFrame];
[button.titleLabel setFont:styleFont];
[self addSubview:button];
} else {
UILabel *label = [[UILabel alloc] initWithFrame:elementFrame];
[label setBackgroundColor:[UIColor clearColor]];
[label setNumberOfLines:maxHeight];
[label setFont:styleFont];
[label setTextColor:styleColor];
[label setText:element.text];
[self addSubview:label];
}
CGSize spaceSize = elementSize.width == 0 ? (CGSize) {0,0} : [@" " sizeWithFont:styleFont];
position.x += elementSize.width + spaceSize.width;
}
position.y += [@"this mother fucker" sizeWithFont:font].height;
[self setSize:CGSizeMake(self.size.width, position.y)];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment