Unable to add custom links to OHAttributeLabel - objective-c

I am using OHAttributeLabel to add custom links to my label's text. The code that I am using is pasted below. It used to work with the older version of OHAttributed label (2010), however with the new version (recently updated), the text in my label are no longer clickable as links.
Can anyone advise what I am missing here?
// Set Question Label
Question *question = self._answerForCell.question;
NSString *questionText = [NSString stringWithFormat:#"Q: %#", question.text];
CustomOHAttributLabel *thisQuestionLabel = (CustomOHAttributLabel *)[self.contentView viewWithTag:QUESTIONLABEL_TAG];
//Set up dictionary for question
NSString *questionStr = [question.text stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSString *urlForQn = [NSString stringWithFormat:#"dailythingsfm://redirect_to/questions/%#/answers?text=%#&nickname=%#&question_id=%#&question_curious=%i&showEveryOneTab=%i", question.slug, questionStr, [[UserInfo sharedUserInfo] getNickname], question.qid, question.curious, 1];
NSString *qnStartIndex = #"0";
NSString *qnLength = [NSString stringWithFormat:#"%i", [questionText length]];
NSDictionary *qnDict = [NSDictionary dictionaryWithObjectsAndKeys:qnStartIndex, #"start", qnLength, #"length", urlForQn, #"url", nil];
NSArray *array = [NSArray arrayWithObject:qnDict];
[thisQuestionLabel setLabelwithText:questionText fontSize:QUESTION_FONT_SIZE andSubStringToURLArrayViaRange:array withHexColor:#"#555555"];
//Method to set the text in UILabel to a custom link
- (void)setLabelwithText:(NSString *)text fontSize:(CGFloat)fontSize andSubStringToURLArrayViaRange:(NSArray *)array withHexColor:(NSString *)textColor
{
NSMutableAttributedString *attrStr = [NSMutableAttributedString attributedStringWithString:text];
[attrStr setFont:[UIFont systemFontOfSize:fontSize]];
[attrStr setTextColor:[UIColor grayColor]];
[self removeAllCustomLinks];
for (NSDictionary *dict in array) {
NSString *start = [dict objectForKey:#"start"];
NSString *length = [dict objectForKey:#"length"];
NSString *url = [dict objectForKey:#"url"];
NSUInteger startIndex = [start intValue];
NSUInteger len = [length intValue];
NSRange range = NSMakeRange(startIndex, len);
[attrStr setFont:[UIFont boldSystemFontOfSize:fontSize] range:range];
[attrStr setTextColor:[UIColor colorWithHexString:textColor] range:range];
[self addCustomLink:[NSURL URLWithString:url] inRange:range];
}
self.attributedText = attrStr;
}

I have to use 'setLink' method instead of addCustomLink for the latest OHAttribute Library (3.2.1)

Related

Get CGRect from NSStringFromCGRect

I stored a frame (CGRect) in a NSStringFromCGRect, how do I later retrieve the rect?
[mDict setObject:NSStringFromCGRect(frame) forKey:#"frame"];
I need to get the data back how?
CGRect frame = [[mDict objectForKey:#"frame"] ..?]
Does a method exist or I have to parse the string manually?
I think you are looking for,
CGRect frame = CGRectFromString([mDict objectForKey:#"frame"]);
I recommend to use NSValue instead of creating a string representation.
NSValue instances are objects and can be put into a dictionary
CGRect frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
NSValue *value = [NSValue valueWithRect:(NSRect)frame];
NSDictionary *dict = #{#"frame" : value};
CGRect frameBack = (CGRect)[dict[#"frame"] rectValue];
NSLog(#"%#", NSStringFromRect(frameBack));
If you need a string representation which is easily reversible, you could use this
CGRect frame = CGRectMake(0.0, 0.0, 100., 100.0);
NSValue *value = [NSValue valueWithRect:(NSRect)frame];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:value];
NSString *base64String = [data base64EncodedStringWithOptions:0];
NSLog(#"%#", base64String);
NSData *dataBack = [[NSData alloc] initWithBase64Encoding:base64String];
NSValue *valueBack = (NSValue *)[NSKeyedUnarchiver unarchiveObjectWithData:dataBack];
CGRect frameBack = (CGRect)[valueBack rectValue];
NSLog(#"%#", NSStringFromRect(frameBack));
Until someone find a better solution this is what I came up with:
-(CGRect) CGRectFromNStringFromCGRect: (NSString *) string {
NSString *newString = [string stringByReplacingOccurrencesOfString:#"{" withString:#""];
newString = [newString stringByReplacingOccurrencesOfString:#"}" withString:#""];
newString = [newString stringByReplacingOccurrencesOfString:#" " withString:#""];
NSArray *array = [newString componentsSeparatedByString:#","];
if ([array count]==4) {
return CGRectMake([array[0] floatValue], [array[1] floatValue], [array[2] floatValue], [array[3] floatValue]);
} else {
return CGRectZero;
}
}
Use Like this:
CGRect frame = [self CGRectFromNStringFromCGRect:[mDict objectForKey:#"frame"];

How can I word wrap with NSMutableAttributedString?

NSArray *myArray = #[#"1st:array1",
#"2nd:array2",
#"3rd:array3"
];
NSString *labelString = [myArray componentsJoinedByString:#"\n"];
In this codelabelStringcan be word wrapped.
But if use NSMutableAttributedString like this
NSAttributedString *resultString = [resultArray componentsJoinedByString:#"\n"];
it can't be joined by #"\n". Any other method is existed? Thanks.
It's not difficult. You just know one thing.
AttributedString can't have \n maybe. So you just put \n in NSString.
And just make NSAttributedString from this NSString.
Here this code. I hope this code help your work.
NSString *commentString;
NSMutableArray *resultArray = [[NSMutableArray alloc]initWithCapacity:50];
for (InstagramComment *comment in comments) {
commentString = [NSString stringWithFormat:#"%#:%#\n", comment.user.username, comment.text];
NSMutableAttributedString *styledCommentString = [[NSMutableAttributedString alloc]initWithString:commentString];
[resultArray addObject:styledCommentString];
}
NSMutableAttributedString *resultString = [[NSMutableAttributedString alloc]init];
for (int i = 0; i < resultArray.count; ++i) {
[resultString appendAttributedString:[resultArray objectAtIndex:i]];
} [cell.comment setAttributedText:resultString];

How to combine 2 strings into one nsatributed string?

NSString * strTimeBefore = [timeBefore componentsJoinedByString:#" "];
NSString * strTimeAfter = [timeAfter componentsJoinedByString:#" "];
I want the resulting string to be an NSAttributedString where the time in strTimeAfter is in bold
You probably want something like:
NSString *boldFontName = [[UIFont boldSystemFontOfSize:12] fontName];
NSString *yourString = [NSString stringWithFormat:#"%# %#", strTimeBefore, strTimeAfter;
// start at the end of strTimeBefore and go the length of strTimeAfter
NSRange boldedRange = NSMakeRange([strTimeBefore length] + 1, [strTimeAfter length]);
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:yourString];
[attrString beginEditing];
[attrString addAttribute:NSFontAttributeName
value:boldFontName
range:boldedRange];
[attrString endEditing];
And my answer is cribbed from Jacob's answer to this very closely related question.
Take two attribute string in that store your first string into one attribute string without changing its attributes, In second attribute string store your second string with changing its attibutes and then append both attribute string into one NSMutableAttributeString Try like this below:-
NSString * strTimeBefore = [timeBefore componentsJoinedByString:#" "];
NSString * strTimeAfter = [timeAfter componentsJoinedByString:#" "];
NSAttributedString *attrBeforeStr=[[NSAttributedString alloc]initWithString:strTimeBefore];
NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
[attributes setObject:[NSColor yellowColor] forKey:NSBackgroundColorAttributeName];
NSFont *font = [[NSFontManager sharedFontManager] fontWithFamily:#"Arial" traits:NSBoldFontMask weight:5 size:14];
[attributes setObject:font forKey:NSFontAttributeName];
NSAttributedString *attrAftStr=[[NSAttributedString alloc]initWithString:strTimeAfter attributes:];
NSMutableAttributedString *string=[[NSMutableAttributedString alloc] init];
[string appendAttributedString:attrBeforeStr];
[string appendAttributedString:strTimeAfter];
Note: You can change font color as well in attribute string, if it is required.

How to create an NSarray with NSAttributedStrings but keeping the attributes within the array?

I want to store different strings with different attributes and store all of them in one array and then display the objects in one label but each object with its respective attribute.
Any suggestions?
EDIT: Solution derived from rmaddy's answer
NSDictionary *redAttrs = #{NSForegroundColorAttributeName:[UIColor redColor]};
NSDictionary *greenAttrs = #{NSForegroundColorAttributeName:[UIColor colorWithRed:0.118 green:0.506 blue:0.000 alpha:1.000]};
NSDictionary *orangeAttrs = #{NSForegroundColorAttributeName:[UIColor orangeColor]};
NSString *stringUm = #"Brazil";
NSString *stringDois = #"USA";
NSString *stringTres = #"England";
NSMutableAttributedString *redString = [[NSMutableAttributedString alloc] initWithString:stringUm];
[redString setAttributes:redAttrs range:NSMakeRange(0,4)];
NSMutableAttributedString *greenString = [[NSMutableAttributedString alloc] initWithString:stringDois];
[greenString setAttributes:greenAttrs range:NSMakeRange(0,2)];
NSMutableAttributedString *orangeString = [[NSMutableAttributedString alloc] initWithString:stringTres];
[orangeString setAttributes:orangeAttrs range:NSMakeRange(0,4)];
NSArray *myStrings = [[NSArray alloc] initWithObjects:redString, greenString, orangeString, nil];
NSLog(#"%#", [myStrings description]);
NSMutableAttributedString *result = [[NSMutableAttributedString alloc]init];
NSAttributedString *delimiter = [[NSAttributedString alloc] initWithString: #", "];
for (NSAttributedString *str in myStrings) {
if (result.length) {
[result appendAttributedString:delimiter];
}
[result appendAttributedString:str];
}
_lblUm.attributedText = result;
Your question is very unclear. But based on your comment to gerrytan's answer, your goal is clearer.
If you have an array of NSAttributedString objects, then you can create a single string by appending them all together with an NSMutableAttributedString.
NSArray *myStrings = ... // your array of NSAttributedString objects
NSMutableAttributedString *result = [[NSMutableAttributedString alloc] init];
// Put this delimiter between each string - change as desired
NSAttributedString *delimiter = [[NSAttributedString alloc] initWithString:#", "];
for (NSAttributeString *str in myStrings) {
if (result.length) {
[result appendAttributedString:delimiter];
}
[result appendAttributedString:str];
}
myLabel.attributedText = result;
UILabel only supports one NSAttributedString. I think what you can do is to place multiple UILabel side by side for each string on the array

Adding Annotations for coordinates MKMapView

I am parsing this JSON file (correctly, it works with the UITextFields):
{"longitude":["37.786793","39.388528"],"latitude":["-122.395416","-78.887734"]}
ind creating MapViews, with the respective annotations in this way:
NSArray *allKeys2 = [DictionaryMap allKeys];
for (int h = 0; h < [allKeys2 count]; h++) {
CGRect mapFrame = CGRectMake( 400, e, 200, 110);
MKMapView *mapView2 = [[MKMapView alloc] initWithFrame:mapFrame];
[image1 addSubview:mapView2];
NSString *key2 = [allKeys2 objectAtIndex:i];
NSObject *obj2 = [DictionaryMap objectForKey:key2];
NSString *address = [NSString stringWithFormat:#"%#", obj2];
float stringFloat = [address floatValue];
float stringFloat2 = [key2 floatValue];
CLLocationCoordinate2D anyLocation;
anyLocation.longitude = stringFloat;
anyLocation.latitude = stringFloat2;
MKPointAnnotation *annotationPoint2 = [[MKPointAnnotation alloc] init]; annotationPoint2.coordinate = anyLocation;
annotationPoint2.title = #"Event";
annotationPoint2.subtitle = #"Microsoft's headquarters2";
[mapView2 addAnnotation:annotationPoint2];
[mapView2.userLocation setTitle:#"I am here"];
[mapView2.userLocation addObserver:self
forKeyPath:#"location"
options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld)
context:NULL];
[mapView2 setShowsUserLocation:NO];
[MapViewArray addObject:mapView2];
if (MapViewArray == nil)MapViewArray = [[NSMutableArray alloc]init];
[MapViewArray addObject: mapView2];
}}
}while(g < f);
...I want the first map view to show the first coordinate pin, and the second to show the second pair of coordinates. But now, it is plotting on all the map views the same pin, corresponding to the last coordinates, and not to the first and second... respectively. This method works for the UITextField text, so I can't find the problem.
Please help!!
EDIT:
NSString *filenameMap = [NSString stringWithFormat:#"%#%#Map", destDir, NavBar.topItem.title];
NSString *MapPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#Map", NavBar.topItem.title]];
[self.restClient loadFile:filenameMap intoPath:MapPath];
NSString *fileContentMap = [[NSString alloc] initWithContentsOfFile:MapPath];
SBJsonParser *parserMap = [[SBJsonParser alloc] init];
NSDictionary *dataMap = (NSDictionary *) [parserMap objectWithString:fileContentMap error:nil];
NSArray *MaparrayLongitude = [dataMap objectForKey:#"longitude"];
NSArray *MaparrayLatitude = [dataMap objectForKey:#"latitude"];
NSDictionary* DictionaryMap = [NSDictionary dictionaryWithObjects:MaparrayLatitude forKeys:MaparrayLongitude];
Another take:
You probably don't want to map your latitudes to longitudes in DictionaryMap. How about making an NSArray of NSDictionaries, where each dictionary has a "latitude" key and a "longitude" key?
Also, you have "[MapViewArray addObject: mapView2]" twice in your code.
And what is "g"? Maybe add some logging to your loop so you can see what's being created?