Updated substring in NSAttributedString - iphone

How I can replace substring in NSMutableAttributedString without adding static range number?
I have a label with this text: #"12 friends", I want to replace 12 (number of friends) with another number (and use the same attributes for this substring) once that it will come from the server, and I can not use the below approach since the number of digits is unknown:
/*wrong approach*/
NSMutableAttributedString *mutableAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:label.attributedText];
[mutableAttributedString replaceCharactersInRange:NSMakeRange(0, 2) withString:counter];
[label setAttributedText:mutableAttributedString];

If the label will always read "x friends" then why not just use a formatted string and pass in the number of friends as a parameter. Of course you could make this whole thing variable for localization, etc. but the basic idea is this:
NSInteger numberFromServer = ...
NSString *string = [NSString stringWithFormat:#"%d friend%#",numberFromServer,((numberFromServer != 1) ? #"s" : #"")];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string];
[label setAttributedText:attributedString];

Related

iOS - Auto-shrink UILabel with Attributed text

I have UILabel which contains two attributed strings separated by a new line.
FIrst string has font size set to 17 and the second one to 14.
I want my first NSMutableAttributedString be resized to minimum font size if its content can't fit in a single line.
Is that possible?
It is pretty simple to configure such UILabel behaviour by setting "auto shrink to minimum font size" in IB for plain text, but don't know how to do it for attributed text.
Here is my code:
NSString *eventName = #"Looong Event Name";
NSString *placeString = #"My place";
eventName = [eventName stringByAppendingString:#"\n"];
NSMutableAttributedString *attrName = [[NSMutableAttributedString alloc] initWithString:eventName];
[attrName addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:17] range:NSMakeRange(0, [eventName length])];
NSMutableAttributedString *attrPlace = [[NSMutableAttributedString alloc] initWithString:placeString];
[attrPlace addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:14] range:NSMakeRange(0, placeString.length)];
[attrPlace addAttribute:NSForegroundColorAttributeName value:[UIColor grayColor] range:NSMakeRange(0, placeString.length)];
NSMutableAttributedString *finalString = [[NSMutableAttributedString alloc] initWithAttributedString:attrName];
[finalString appendAttributedString:attrPlace];
UILabel *nameLabel = (UILabel *)[cell viewWithTag:100];
nameLabel.attributedText = finalString;
I guess this is a follow on from your earlier question.
I don't think you can do this automatically, but there is a size method of NSAttributedString which you can use to check if your string is too big, and adjust yourself if required.

Get first sentence of textview

I am trying to get the first sentence of a text view. I have the following code but am getting an out of bounds error. Thank You. Or are there any ways that aren't really complex.
-(IBAction)next:(id)sender
{
NSRange ran = [[tv.text substringFromIndex:lastLocation] rangeOfString:#". "];
if(ran.location != NSNotFound)
{
NSString * getRidOfFirstHalfString = [[tv.text substringFromIndex:lastLocation] substringToIndex:ran.location];
NSLog(#"%#",getRidOfFirstHalfString);
lastLocation+=getRidOfFirstHalfString.length;
}
How about:
NSString *finalString = [[tv.text componentsSeparatedByString:#"."] objectAtIndex:0] // Get the 1st part (left part) of the separated string
Go through the textview's text and divide the text into separate components where you find a period by calling componentsSeperatedByString on tv.text. You want the first sentence, which would be the 0th object in the array.
I know you've already accepted an answer to this question, but you might want to consider using the text view's tokenizer instead of just searching for the string ". " The tokenizer will automatically handle punctuation like !, ?, and closing quotes. You can use it like this:
id<UITextInputTokenizer> tokenizer = textView.tokenizer;
UITextRange *range = [tokenizer rangeEnclosingPosition:textView.beginningOfDocument
withGranularity:UITextGranularitySentence
inDirection:UITextStorageDirectionForward];
NSString *firstSentence = [textView textInRange:range];
If you want to enumerate all of the sentences, you can do it like this:
id<UITextInputTokenizer> tokenizer = textView.tokenizer;
UITextPosition *start = textView.beginningOfDocument;
while (![start isEqual:textView.endOfDocument]) {
UITextPosition *end = [tokenizer positionFromPosition:start toBoundary:UITextGranularitySentence inDirection:UITextStorageDirectionForward];
NSString *sentence = [textView textInRange:[textView textRangeFromPosition:start toPosition:end]];
NSLog(#"sentence=%#", sentence);
start = end;
}
Try checking that the substring was actually found.
NSRange ran = [tv.text rangeOfString:#". "];
if(ran.location != NSNotFound)
{
NSString * selectedString = [tv.text substringToIndex:ran.location];
NSLog(#"%#",selectedString);
}
You could alternatively try using NSScanner like this:
NSString *firstSentence = [[NSString alloc] init];
NSScanner *scanner = [NSScanner scannerWithString:tv.text];
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:#"."];
[scanner scanUpToCharactersFromSet:set intoString:&firstSentence];
I'm not sure if you want this, but since you want the first sentence, you could append a period (you probably know how to do this, but it doesn't hurt to show it anyway):
firstSentence = [firstSentence stringByAppendingFormat:#"."];
Hope this helps!
PS: If it didn't work for you, maybe the text view doesn't actually contain any text.

How to add UILabel between two strings

i have this code to show some texts in a UITextview..i just want to add a UILabel between these strings.i am getting text in this formate, 1 this is first text 2 this is second text 3 this is third text,,i want to add or append UILabel between numeric character and text.my code for showing text is
NSMutableString *combined = [NSMutableString string];
for(NSUInteger idx = 0; idx < [delegatee.allSelectedVerseEnglish count]; idx++) {
[combined appendFormat:#" %d %#",
idx + 1,
[delegatee.allSelectedVerseEnglish objectAtIndex:idx]];
}
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
NSNumber * n = [f numberFromString:combined];
NSLog(#"N: %#", n);
maintextview.text =combined;
combined is the text in the above formate ,and maintextview is the UITextview.
am also getting the string range between two sentence
- (void)textViewDidEndEditing:(UITextView *)textView
{
if (textView == maintextview) {
mainpopupview.frame =CGRectMake(0, 0, 768, 1004) ;
[self.view addSubview:mainpopupview];
NSRange selectedRange = [textView selectedRange];
NSString *backString = [maintextview.text substringToIndex:selectedRange.location];
NSRange backRange = [backString rangeOfString:#" " options:NSBackwardsSearch];
NSRange backRangee = [backString rangeOfString:#" " options:NSBackwardsSearch];
int myRangeLenght = backRangee.location - backRange.location;
NSRange myStringRange = NSMakeRange (backRange.location, myRangeLenght);
NSString *forwardString = [maintextview.text substringFromIndex:backRange.location];
NSLog(#"%#",[[forwardString componentsSeparatedByString:#" "] objectAtIndex:1]);
NSLog (#"%#", [maintextview.text substringWithRange:myStringRange]);
NSString * myStringTxt = [[forwardString componentsSeparatedByString:#" "] objectAtIndex:1];
NSLog(#"1 %#", myStringTxt);
// maintextview.textColor = [UIColor yellowColor];
NSRange myStringRangee = [maintextview.text rangeOfString:myStringTxt];
[maintextview select:self];
maintextview.selectedRange = myStringRangee;
is there any way to do this.
Thanks in advance.
I don't know what user interaction you need here, but if you're just displaying the text for the user, but could you replace your UITextView with a UIWebView (loading static text via loadHTMLString:baseURL:, using html markup to set the color of the text)? I refer to the UITextView documentation:
This class does not support multiple styles for text. The font, color,
and text alignment attributes you specify always apply to the entire
contents of the text view. To display more complex styling in your
application, you need to use a UIWebView object and render your
content using HTML.
If you really need to do this with separate UI controls (much more complicated than just using a UIWebView) you don't "insert" the UILabel in the text, but rather you'd probably have one control for the text up to the point of the color change, another control for the text of a different color or what have you, another control for the rest of the text. It would get hairly pretty quickly (unless it was laid out like a grid, and even then it's a hassle compared to a UIWebView).

iOS localization, label with number and word together

i want to localize my game. some of my label is like [#"Score: %i", score], and the score can be any number. so can i still use strings file localization?
this is what i do currently, but a lot of work
CCLabelTTF* bestLabelWord = [Helper createLocalizedLabelWithStringUpperCase:#"BEST" color:ccBLACK];
CCLabelTTF* bestLabelNumber = [Helper createUnlocalizedLabelWithString:[NSString stringWithFormat:#"%i", bestScore] color: ccBLACK];
bestLabelWord.anchorPoint = ccp(0, 0.5f);
bestLabelNumber.anchorPoint = ccp(0, 0.5f);
bestLabelWord.position = ccp(menuPosX, menuPosY2);
bestLabelNumber.position = ccp(menuPosX + bestLabelWord.contentSize.width + 5, menuPosY2);
[self addChild:bestLabelWord z:kZLabel];
[self addChild:bestLabelNumber z:kZLabel];
here i separate #"Score" and #"%i", score into 2 labels (word and number) and place them separately.
so how can i put them into one label? can i put like "NSString stringWithFormat" in localization.strings file?
Yes, you can do this. It looks like this (uncompiled; hopefully there is no typo):
NSString *scoreFormat = NSLocalizedString(#"Score: %d", #"Score format");
NSString *scoreString = [NSString stringWithFormat:scoreFormat, bestScore];
Your strings file for this in English would be:
/* Score format */
"Score: %d" = "Score: %d";
There is no difference between %d and %i. They are both specified by the standard. I personally prefer to express that it is "decimal" (vs. %x hexadecimal) rather than that it is an "integer" (vs. %f float). But it does not matter.
You should include the entire format statement in the strings file. You are localizing the entire format statement Score: %d. The rationale for this is to permit languages where the order might be different. For example, if there were a language where the correct translation were "%d score" or a language where to make sense you would have to say the equivalent of Score: %d points or Score: %d number.
If you don't want this kind of localization, and you will always put a colon after the label and a number after that, no matter the language, then you can localize just the label as you were in your original code, or like this:
NSString *localizedLabel = NSLocalizedString(#"Score", #"Score");
NSString *scoreString = [NSString stringWithFormat:#"%#: %d", localizedLabel, bestScore];
You should avoid calling NSLocalizedString with a variable parameter as you're suggesting. This is confusing, and can get in the way of using genstrings to create your strings file. That said, the following code is not a problem:
NSString * const kScoreLabelKey = #"Score";
NSString * const kPriceLabelKey = #"Price";
NSString *GetLocalizedStringForKeyValue(NSString *key, NSInteger value)
{
NSString *label = [[NSBundle mainBundle] localizedStringForKey:key value:nil table:#"Labels"];
NSString *valueLabel = [NSString stringWithFormat:#": %d", value];
return [label stringByAppendingString:valueLabel];
}
...
NSString *label = GetLocalizedStringForKeyValue(kScoreLabelKey, bestScore);
...
(In Labels.strings):
"Score" = "Score";
"Price" = "Price";
Things to note:
I created a separate strings file for this called Labels.strings. That way it doesn't impact using genstrings and the main Localizeable.string.
I used string constants for the keys. That puts all the strings used in one place at the top of the file, making it easy to audit against Labels.strings.

Substring with asterisks in NSString

Hi friends i want to display credit card number in table view cell,so i want to display only last four characters like XXXXXXXXXX1111 first charecters is replaced with x or some other character how can i do this can any one help me
i have tried like bellow
NSString *CardNumber = [CardNumberValues objectAtIndex:indexPath.row];
NSRange subStringRange = NSMakeRange(0,[CardNumber length]-4);
NSMutableCharacterSet *NumSet = [NSMutableCharacterSet characterSetWithRange:subStringRange];
CardNumber = [[CardNumber componentsSeparatedByCharactersInSet:NumSet] componentsJoinedByString:#"X"];
cell.CardNumber.text = CardNumber;
but its not working can u suggest any reference or code...
Use this
NSString *CardNumber = #"12345678901234";
NSString *str_padding=#"";
NSRange subStringRange = NSMakeRange(0,[CardNumber length]-4);
str_padding =[str_padding stringByPaddingToLength:subStringRange.length withString:#"X" startingAtIndex:0];
CardNumber = [CardNumber stringByReplacingOccurrencesOfString:[NSString stringWithFormat:#"%#",[CardNumber substringToIndex:subStringRange.length]] withString:str_padding];
NSLog(#"%#",CardNumber);
NSString *cardNumber = [NSString stringWithFormat: #"XXXX-XXXX-XXXX-%#", [[CardNumberValues objectAtIndex:indexPath.row] subStringWithIndex:12]];
cell.CardNumber.text = cardNumber;
I am assuming that card numbers are 16 digits.