UILabel Multiple Lines - objective-c

I have a UILable which displays text as I press buttons. The text is from an attributed string. One of the buttons calls for a superscript attribute:
string = [[NSMutableAttributedString alloc]initWithString:#"A"];
[string addAttribute:NSFontAttributeName value:(font) range:NSMakeRange(string.length-1, 1)];
[string addAttribute:(NSString*)kCTSuperscriptAttributeName value:#"1" range:NSMakeRange(string.length-1, 1)];
[string2 appendSttributedString: string];
label.attributedText = string2;
This code works as long as string2 fits onto one line in the UILable. When the text begins to span two lines at first it appears as it should. However when the kCTSuperscriptAttributeName superscript attribute is added the second line of the label disappears and gets truncated. Im not sure whats going on. Anyone have an idea?

Make sure that you are setting the numberOfLines property on the UILabel to be 2 or something, so that the label doesn't truncate beyond the first line. Hope this helps!

Did you try 'NSBaselineOffsetAttributeName' for NSAttributedString?
-(void)setText:(id)text withPrefixText:(id)prefixText andSuffixText:(id)suffixText
{
NSString * compondText = [self textByCompoundingText:text withPrefixText:prefixText WithsuffixText:suffixText];
NSMutableAttributedString * attributedCompoundText = [[NSMutableAttributedString alloc] initWithString:compondText];
NSMutableDictionary * prefixTextAttributes = [#{} mutableCopy];
prefixTextAttributes[NSFontAttributeName] = _prefixTextFont? _prefixTextFont:self.font;
prefixTextAttributes[NSForegroundColorAttributeName] = _prefixTextColour? _prefixTextColour:self.textColor;
NSNumber *baselineOffSet =[NSNumber numberWithUnsignedInteger:_prefixTextVerticalPositionning];
prefixTextAttributes[(NSString*)NSBaselineOffsetAttributeName] = baselineOffSet;
NSMutableDictionary * suffixTextAttributes = [#{} mutableCopy];
suffixTextAttributes[NSFontAttributeName] = _suffixTextFont? _suffixTextFont:self.font;
suffixTextAttributes[NSForegroundColorAttributeName] = _suffixTextColour ?_suffixTextColour:self.textColor;
baselineOffSet = [NSNumber numberWithUnsignedInteger:_suffixTextVerticalPostioning];
suffixTextAttributes[(NSString*)NSBaselineOffsetAttributeName] = baselineOffSet;
if(prefixText)
[attributedCompoundText addAttributes:prefixTextAttributes range:[compondText rangeOfString:prefixText]];
if(suffixText)
[attributedCompoundText addAttributes:suffixTextAttributes range:[compondText rangeOfString:suffixText]];
self.attributedText = attributedCompoundText;
}

Related

NSTextStorage - How to find return chars (new line) in a text

In an NSTextStorage I insert time strings at the current pointer location like this :
NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString: #"00:00:00"];
[attrString autorelease];
int pos = [self selectedRange].location;
[[self textStorage] insertAttributedString: attrString atIndex:pos];
So far so good, it works perfect. But now I want to position the pointer at the beginning of the next line. Obviously this is right after the next return char.
Now how to find the next return char in textStorage and position the pointer there ?
I have not found any hint in the web for this task. Please help ...
You won't find a method to set the cursor (more precise: selection with zero length) in NSTextStorage's API, because it is a storage, having no selection. The selection is a property of the text view. This is the result of MVC. Simply do a check: You can have many text views displaying the same text. Obviously each one needs its own selection.
What you have to do is to get the position of the next paragraph (this is better than searching for \n) and set this as a selection for the text view.
NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString: #"00:00:00"];
[attrString autorelease]; // You should *really* use ARC
int pos = [self selectedRange].location;
[[self textStorage] insertAttributedString: attrString atIndex:pos];
// Get the next paragraph
NSString *text = self.textStorage.string;
NSRange restOfStringRange = NSMakeRange( pos, [text length]-pos );
NSUInteger nextParagraphIndex;
// You have to look to the start of the next paragraph
[text getParagraphStart:&nextParagraphIndex end:NULL contentsEnd:NULL forRange:restOfStringRange];
NSTextView *view = self.textView; // Or where ever you get it from
view.selectedRange = NSMakeRange(nextParagraphIndex, 0);
Typed in Safari, not tested, just to show the basic approach.

Superscript cents in an attributed string

I'm trying to get my label to look like so:
But using attributed string, I managed to get this result:
My code:
NSString *string = [NSString stringWithFormat:#"%0.2f",ask];
NSMutableAttributedString *buyString = [[NSMutableAttributedString alloc] initWithString:string];
[buyString addAttribute:NSFontAttributeName
value:[UIFont systemFontOfSize:15.0]
range:NSMakeRange(2, buyString.length - 2)];
self.labelBuy.attributedText = buyString;
As you see, the numbers after the dot, stay below, and I would like to pop them to the top as the first example.
Is there any way to set attributed string frame?
You have to use NSBaselineOffsetAttributedName.
From the doc:
NSBaselineOffsetAttributeName
The value of this attribute is an
NSNumber object containing a floating point value indicating the
character’s offset from the baseline, in points. The default value is
0. Available in iOS 7.0 and later.
From your example:
[buyString addAttribute:NSBaselineOffsetAttributeName
value:#(10.0)
range:NSMakeRange(2, buyString.length - 2)];
You may have to change the value to fit your needs.
Why not actually use superscript? You must first #import "CoreText/CoreText.h"
[buyString addAttribute:(NSString *)kCTSuperscriptAttributeName
value:#1
range:NSMakeRange(2, buyString.length - 2)];

Can I add adress lines to a Text View from contacts

Is it possible to add all the lines of an address to a text view, so far I can only get the last line to show up in the view adresslines.
self.adresslines.text = (NSString *)(CFDictionaryGetValue(dictionary, kABPersonAddressCityKey));
self.adresslines.text = (NSString *)(CFDictionaryGetValue(dictionary, kABPersonAddressStreetKey));
self.adresslines.text = (NSString *) (CFDictionaryGetValue(dictionary, kABPersonAddressZIPKey));
As you have it now you are setting the text view's text with each line of the address. You want to append, not replace. Something like this will work:
NSMutableString *text = [NSMutableString string];
[text appendString:(NSString *)(CFDictionaryGetValue(dictionary, kABPersonAddressCityKey))];
[text appendString:#"\n"];
[text appendString:(NSString *)(CFDictionaryGetValue(dictionary, kABPersonAddressStreetKey))];
[text appendString:#"\n"];
[text appendString:(NSString *) (CFDictionaryGetValue(dictionary, kABPersonAddressZIPKey))];
self.addresslines.text = text;
Of course you can add checks in here to avoid blank lines or add other formatting as desired.

Custom Formatter Weird Behavior

I have a custom NSFormatter linked to 4 NSTextFields. When I change the values of my text fields manually, everything works fine. But when I change it through a combo box. I get an error looking like this:
-[__NSCFNumber length]: unrecognized selector sent to instance 0xc0c3
I've noticed that the application continuously sends this error and that the instance is always the same (0xc0c3). Also, when my NSTextFields aren't linked to my custom formatter, everything works well, even through the combo box.
Do you guys know what may be the source of the problem?
Thanks in advance!
Here's some code:
Combo box action:
- (void)subnetMaskByNumberOfSubnetBits:(id)sender{
// ------- Sets the subnet mask when the user selects the number of bits
NSNumberFormatter *stringToNumber = [[NSNumberFormatter alloc] init];//TURN A STRING INTO A NUMBER
NSNumber *selectedAmountOfBits = [[NSNumber alloc] init];//CONTAINS THE SELECTED NUMBER OF BITS
selectedAmountOfBits = [stringToNumber numberFromString:[sender objectValueOfSelectedItem]];
[self changeSubnetMaskUsingNumberOfMaskBits:selectedAmountOfBits];
//RELEASE
[stringToNumber release];
}
-(void)changeSubnetMaskUsingNumberOfMaskBits:(NSNumber *)numberOfMaskBitsSelected{
// --------- Change the subnet mask based on the number of bits
NSInteger numberOfFullOctets;
NSInteger valueOfLastOctet;
NSInteger octetCounter;
NSMutableDictionary *subnetMaskFields = [[NSMutableDictionary alloc] init];
//Contains keys to all the outlets
[subnetMaskFields setObject:subnetMaskOctet1 forKey:#"subnetMaskField1"];
[subnetMaskFields setObject:subnetMaskOctet2 forKey:#"subnetMaskField2"];
[subnetMaskFields setObject:subnetMaskOctet3 forKey:#"subnetMaskField3"];
[subnetMaskFields setObject:subnetMaskOctet4 forKey:#"subnetMaskField4"];
//NUMBER OF FULL OCTETS AND VALUE OF LAST OCTET
numberOfFullOctets = [numberOfMaskBitsSelected intValue]/8;
valueOfLastOctet = 256 - pow(2, 8 - ([numberOfMaskBitsSelected intValue] - (8 * ([numberOfMaskBitsSelected intValue]/8)))); //Big complicated formula
//-------Setting the fields------//
//SETTING THE FIELDS OF FULL OCTETS
for (octetCounter = 1; octetCounter <= numberOfFullOctets; octetCounter++) {
[[subnetMaskFields objectForKey:[NSString stringWithFormat:#"subnetMaskField%i", octetCounter]] setStringValue:#"255"];
}
//SETTING THE FIELD OF THE INCOMPLETE OCTET
[[subnetMaskFields objectForKey:[NSString stringWithFormat:#"subnetMaskField%i", octetCounter]] setIntegerValue:valueOfLastOctet];
//FILLING THE ZER0S
while (octetCounter < 4) {
octetCounter++;
[[subnetMaskFields objectForKey:[NSString stringWithFormat:#"subnetMaskField%i", octetCounter]] setStringValue:#"0"];
}
//RELEASE
[subnetMaskFields release];
}
The problem is this line of code:
[[subnetMaskFields objectForKey:[NSString stringWithFormat:#"subnetMaskField%i", octetCounter]] setIntegerValue:valueOfLastOctet];
From what I understand, since the NSFormatter needs to get the string value of my text field, I cannot set the text field as an integer. This line of code
[[subnetMaskFields objectForKey:[NSString stringWithFormat:#"subnetMaskField%i", octetCounter]] setStringValue:[NSString stringWithFormat:#"%ld", valueOfLastOctet]];
solves the problem.

Using a String representing the name of a variable to set the variable

This is a basic example that I know can be simplified, but for testing sake, I would like to do this in such a way. I want to set a variable based on an appending string (the variables "cam0" and "pos1" are already declared in the class). The appending string would essentially be an index, and i would iterate through a loop to assign cameras (cam0, cam1..) to different positions (pos0, pos1..).
cam0 is defined as an UIImageView
pos1 is defined as a CGRect
This works for a NSString Variable named coverIndex:
NSString* text = [[NSString alloc] initWithString:#""];
NSLog(#"%#",(NSString *)[self performSelector:NSSelectorFromString([text stringByAppendingString:#"coverIndex"])]);
The correct string that I set for coverIndex was logged to the Console.
Now back to my UIImageView and CGRect. I want this to work.
NSString* camText = [[NSString alloc] initWithString:#"cam"];
NSString* posText = [[NSString alloc] initWithString:#"pos"];
[(UIImageView *)[self performSelector:NSSelectorFromString([camText stringByAppendingString:#"0"])] setFrame:(CGRect)[self performSelector:NSSelectorFromString([posText stringByAppendingString:#"1"])]];
My error is "Conversion to non-scalar type requested"
This is the only way I found to do this sort of thing (and get the NSLog to work), but I still believe there is an easier way.
Thank you so much for any help :)
Use KVC, it's an amazing piece of technology that will do just what you want:
for (int index = 0; index < LIMIT; index++) {
NSString *posName = [NSString stringWithFormat:#"pos%d", index];
CGRect pos = [[self valueForKey:posName] CGRectValue];
NSString *camName = [NSString stringWithFormat:#"cam%d", index];
UIImageView *cam = [self valueForKey:camName];
cam.frame = pos;
}
One way you can do this would be to create your cameras in a dictionary and use those special NSStrings to key in to it. Like,
NSMutableDictionary *myCams;
myCams = [[myCams alloc] init];
[myCams addObject:YOUR_CAM0_OBJECT_HERE forKey:#"cam[0]"];
[myCams addObject:YOUR_CAM1_OBJECT_HERE forKey:#"cam[1]"];
NSString camString = #"cam[0]"; // you'd build your string here like you do now
id theCamYouWant = [myCams objectForKey:camString];