I need to animate label text with #"text . ", #"text . ", #"text . ", #"text ."
So user will see only dot animation. I use a center alignment for the label text.
I use timer for that purposes:
- (void)processTimerFired:(NSTimer *)timer {
NSMutableDictionary *dict = [timer userInfo];
NSMutableString *string = [[dict objectForKey:#"label"] mutableCopy];
int dotNumber = [[dict objectForKey:#"dot"] intValue];
if (dotNumber == 3) {
dotNumber = 1;
}
else {
dotNumber += 1;
}
[dict setObject:#(dotNumber) forKey:#"dot"];
for (int i = 1; i < 4; i++) {
if (i == dotNumber) {
[string appendString:#"."];
}
else {
[string appendString:#" "];
}
}
self.informationLabel.text = string;
}
on iOS 6 everything is OK, but on iOS 7 it seems that xcode reduces the number of spaces, so the origin of the text always becomes different. And that's why it seems that text is shaken.
I tried to add "+" at the end for test. And everything became OK. So It seems that xcode removes 'excess' spaces only when there is not other symbol after that.
What if you replace the space #" " with a Unicode non-breakable space #" " (obtained by Alt-space on a Mac) ?
I'm doing test with that issue and I'm seen that you need to center the text to right. That's my code:
self.text = #[#"Text. ",#"Text . ", #"Text ."];
[self.shorLabel setTextAlignment:NSTextAlignmentCenter];
[self doAnimation:#0];
And doAnimation method:
- (void) doAnimation: (NSNumber *)index
{
int indexInt = ([index intValue] +1)%3;
[self.shorLabel setText:self.text[indexInt]];
[self.shorLabel sizeToFit];
[self.shorLabel setFrame:CGRectMake((self.view.frame.size.width - self.shorLabel.frame.size.width)/2, self.shorLabel.frame.origin.y, self.shorLabel.frame.size.width, self.shorLabel.frame.size.height)];
[self performSelector:#selector(doAnimation:) withObject:#(indexInt) afterDelay:0.2];
}
Related
This is my Button method. When I press the button it's value is every time increment one & display into Label. Then it's reach 6 then convert like 1.0 , 7 = 1.1, 8 = 1.2 , 12 like 2.0 like cricket over format.
How can I do that?
-(void)OneNoBTNPressedMethod
{
// LBL it's my label & display the text
NSString * overStorage = LBL.text;
// perform the addition operation
CalcOperation operation;
operation = Plus;
//add one every time when we press the button
NSString * overOneBTNStr = [NSString stringWithFormat:#"1"];
NSString *overVal = overOneBTNStr;
LBL.text= [NSString stringWithFormat:#"%qi",[overVal longLongValue]+[overStorage longLongValue]];
}
Thanx in advance..
It worked for me. Hope it works for you as well. Assuming your LBL contains "1" as initial text. hope it helps
- OneNoBTNPressedMethod {
NSString *str = LBL.text;
NSArray *arr = [str componentsSeparatedByString:#"."];
if ([arr count] == 1) {
if ([LBL.text intValue] >= 5) {
LBL.text = [NSString stringWithFormat:#"%i.%i",0,0];
} else {
LBL.text = [NSString stringWithFormat:#"%i",[LBL.text intValue] + 1];
}
} else if ([arr count] == 2) {
if ([[arr objectAtIndex:1] intValue] >= 5) {
int left = [[arr objectAtIndex:0] intValue] + 1;
LBL.text = [NSString stringWithFormat:#"%i.%i",left,0];
} else {
LBL.text = [NSString stringWithFormat:#"%i.%i",[[arr objectAtIndex:0] intValue],[[arr objectAtIndex:1] intValue] + 1];
}
}
}
Try this logic
Let `int num` is count
Then
numBeforeDecimal = num/6;
numAfterDecimal = num%6;
Concatenate both number
[NSString stringWithFormat: #"%d.%d",numBeforeDecimal,numAfterDecimal];
Something strange is going on. When I reassign an NSString to my subString variable near the bottom of my code. It seems that the value of subString is empty in the output. I don't know if objectAtIndex is returning something weird or it's a memory problem. If I create a new variable instead of reassigning the value of subString, I can print see the correct value in the output console. If anyone could help me figure this out. It'd be greatly appreciated.
NSString *subString = #"";
if ([text length] > 0)
{
UITextRange *selectedRange = [_textView selectedTextRange];
UITextPosition *cursorPosition = [_textView positionFromPosition:selectedRange.start offset:0];
UITextRange *subTextRange = [_textView textRangeFromPosition:_textView.beginningOfDocument toPosition:cursorPosition];
subString = [textView textInRange:subTextRange];
}
NSLog(subString);
NSLog(#" %s", [subString hasSuffix:#" "] ? "TRUE" : "FALSE");
BOOL hasSpaceSuffix = [subString hasSuffix:#" "];
NSLog(#" %s", _taggingInProgress ? "TRUE" : "FALSE");
NSArray *substringArray = [[subString componentsSeparatedByString:#" "] retain];
if ([substringArray count] > 1) {
int index = [substringArray count];
if ([[substringArray objectAtIndex:index-1] isEqualToString:#" "])
{
NSLog(#"1st");
subString = [substringArray objectAtIndex:index-2];
NSLog(subString);
}
else
{
NSLog(#"2nd");
subString = [substringArray objectAtIndex:index-1];
NSLog(subString);
}
NSLog(#"AFTER");
NSLog(subString);
}
I think you need to use:
subString = [NSString stringWithString:[substringArray objectAtIndex:index]];
...fixed...
I've got a problem with an UITextView and one of its delegate methods in my navigation based app:
- (BOOL)textView:aView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
I managed to limit the max length of text the user can input using the above method. But I'm using a leaky array for that matter I think.
The problem is:
I want to save the amount of typed characters right in the very moment the user enters the last line of my textview. I then use that value to calculate the string length - which I compare to the textview's content size to set a limit. The code works fine - but since the method it's inside of is updating with every text input, I'm having trouble releasing the array in the right moment.
Here's some code:
if (numLines == 9)
{
if (!numCharsArray)
{
numCharsArray = [[NSMutableArray alloc] initWithCapacity:1]; // Stack trace gives this line 3,3% of the leak.
}
numChars = tView.text.length;
NSNumber *number = [[NSNumber alloc] initWithInteger:numChars]; // This line gets 77,3%.
[numCharsArray addObject:number]; // This line gets the rest, 24,3%.
[number release];
startChars = [[numCharsArray objectAtIndex:0] integerValue];
NSString *lastLine = [[NSString alloc]initWithString:[[tView text] substringFromIndex:startChars]];
CGSize lineSize = [lastLine sizeWithFont:tView.font forWidth:tView.contentSize.width lineBreakMode:UILineBreakModeWordWrap];
[lastLine release];
if (range.length > text.length)
{
return YES;
}
else if (numLines == 9 && lineSize.width >= tView.contentSize.width - 45)
{
return NO;
}
}
else
{
numCharsArray = nil;
/*
if(numCharsArray)
{
[numCharsArray release];
}
*/
}
I tried the out-commented statement above, but that gives me an app crash once I leave the last line of the textview. And as you can see in the code comments - without releasing the array I get a leak.
So how and where do I release that array correctly - keeping it safe while the user is on the last line?
Just replace with
first one
numCharsArray = [NSMutableArray array]; // you do not need to release
//explicitly as its autorelease numberWithInt
second one
NSNumber *number = [NSNumber numberWithInt:numChars]; //autorelease
NSString *lastLine = [[tView text] substringFromIndex:startChars];
I know NSString has methods that determine the frame size for it, using NSString UIKit Additions, sizeWithFont......
How about the other way around? I mean if I have a fixed frame size, how do I know how many characters or words for a NSString that can fit into it?
If I know this, I can cut off the NSString easily.
thanks
It might not be the most elegant solution, but you could do something like this:
- (NSString *)string:(NSString *)sourceString reducedToWidth:(CGFloat)width withFont:(UIFont *)font {
if ([sourceString sizeWithFont:font].width <= width)
return sourceString;
NSMutableString *string = [NSMutableString string];
for (NSInteger i = 0; i < [sourceString length]; i++) {
[string appendString:[sourceString substringWithRange:NSMakeRange(i, 1)]];
if ([string sizeWithFont:font].width > width) {
if ([string length] == 1)
return nil;
[string deleteCharactersInRange:NSMakeRange(i, 1)];
break;
}
}
return string;
}
Then call it like this:
NSString *test = #"Hello, World!";
CGFloat width = 40.0;
UIFont *font = [UIFont systemFontOfSize:[UIFont labelFontSize]];
NSString *reducedString = [self string:test reducedToWidth:width withFont:font];
NSLog(#"%#", reducedString);
You cannot know/determine the number of characters that fits in a UILabel with fixed width because some characters are smaler than others, eg l and m.
There are two options:
Use Mono-Space-Fonts (each character has also a fixed width). Then determine the width for one char in your font with your font-size and calculate the number of chars
Allow any number of characters and check on insert if the inserted characters fit.
You have to know what behaviour you want to have. What should happen if there is text that does not fit. If you only want to truncate (like the solution of mortenfast does) then just use UILineBreakModeTailTruncation for the lineBreakMode-property of your UILabel (there are more options, like TruncateHead, Clip, Word Wrap)
Or you just just use the lineBreak property and set it to NSLineBreakByCharWrapping and move on with your life. https://stackoverflow.com/a/29088337/951349
Thanks #Morten. I've updated the sample code to handle word separation. It also eliminates extra spaces in between words. It has not been tested in the field, but my tests have, thus far, proven OK. Please update at your leisure if you find improvements or bug/glitch fixes.
-(NSString*)string:(NSString*)sourceString reducedToWidth:(CGFloat)width withFont:(UIFont*)font {
// if full string is within bounds, simply return the full string
if( [sourceString sizeWithFont:font].width <= width ) return sourceString;
// break up string into words. if <= 1 word, return original string
NSArray* words = [sourceString componentsSeparatedByString:#" "];
NSInteger numWords = [words count];
if( numWords <= 1 ) return sourceString;
// our return var. we populate as we go
NSMutableString* str = [NSMutableString string];
// temp var to test with before adding to return string
NSMutableString* strTemp = [NSMutableString string];
// string to hold word LESS spaces
NSString* strWordTemp = nil;
// the word we're currently on
NSInteger numWord = 0;
// whether we need to add a space (when not last word)
Boolean addSpace = NO;
// loop through our words....
for( NSString* strWord in words ) {
// which word we're on
numWord++;
// eliminate white space
strWordTemp = [strWord stringByReplacingOccurrencesOfString:#" " withString:#""];
// if this word is empty or was a space(s), skip it
if( [strWordTemp isEqualToString:#""] ) continue;
// append to temp string
[strTemp appendString:strWordTemp];
// if we're still within the bounds...
if( [strTemp sizeWithFont:font].width <= width ) {
// default = no extra space
addSpace = NO;
// if we're not the last word, add a space & check for length
if( numWord < numWords ) {
[strTemp appendString:#" "];
// if adding space made it too long, then just don't add it!
if( [strTemp sizeWithFont:font].width > width ) {
// it was too long with space, so we'll just add word
[str appendString:strWordTemp];
break;
}
// otherwise, it's OK to add the space
else addSpace = YES;
}
// append to return string and continue
[str appendFormat:#"%#%#", strWordTemp, ( addSpace ? #" " : #"" )];
}
// otherwise, we're done
else break;
}
// return our result
return str;
}
I Spent 5 hours try to figure a way for that..i'm trying to do a hangman app for iphone and the method below is the method that should be called when the player chooses a character and it match the chosen word..
-(void)replaceTheHiddenTextWithNewText:(NSString*)character{
NSString *fullTextField = fullText.text;
int textCount = [hiddenText.text length];
NSString *theRiddle;
for (int i = textCount-1 ; i>=0; i--) {
NSString *hiddenTextField = [[NSMutableString alloc] initWithString:hiddenText.text];
NSString *aChar=[fullTextField substringWithRange:NSMakeRange(i/3,1)];
if ([aChar isEqualToString:#" "]) {
theRiddle= [hiddenTextField stringByReplacingCharactersInRange:NSMakeRange(i, 1) withString:#" "];
}else if ([aChar isEqualToString:character]) {
theRiddle =[hiddenTextField stringByReplacingCharactersInRange:NSMakeRange(i, 1) withString:aChar];
}else{
theRiddle = [hiddenTextField stringByReplacingCharactersInRange:NSMakeRange(i, 1) withString:#"_"];
}
hiddenTextField = theRiddle;
}
hiddenText.text=theRiddle;
}
the problem is stringByReplacingCharactersInRange doesn't replace the character, it appends it to the underscore what am I doing wrong here?
Best Regards,
M Hegab
Just played around with your code. It does not work, but stringByReplacingCharactersInRange is not your problem.
Your game logic doesn't work like it should. Get a pen and a sheet of paper and "manually" loop through your for loop to see that this must be wrong.
Next time, if you've stared at code for half an hour, take a pen. This will save you at least 4 hours :-)
There are some issues with your code. Assume Kartoffelkäfer is the word you are looking for, and the user enters the letter f.
for (int i = textCount-1 ; i>=0; i--) {
NSString *hiddenTextField = [[NSMutableString alloc] initWithString:hiddenText.text];
// you are creating this string in every loop from the text of a (I guess) UITextField.
// I don't know what the content of this text is but I guess it is suppossed to be `______________`
// in every loop you replace the word where you replaced the _ with the correct letter with the string from the textfield.
// Btw, you are leaking this string.
NSString *aChar=[fullTextField substringWithRange:NSMakeRange(i/3,1)];
// Kartoffelkäfer has 14 chars so i is 13. And 13/3 is 4. And the character at index 4 is o
// In the next loop i is 12. And 12/3 is 4, too.
// next three loops will give you index 3. Then you get three times index 2, and so one.
// you never reach the letter f, anyway.
if ([aChar isEqualToString:#" "]) {
theRiddle= [hiddenTextField stringByReplacingCharactersInRange:NSMakeRange(i, 1) withString:#" "];
}else if ([aChar isEqualToString:character]) {
theRiddle =[hiddenTextField stringByReplacingCharactersInRange:NSMakeRange(i, 1) withString:aChar];
}else{
theRiddle = [hiddenTextField stringByReplacingCharactersInRange:NSMakeRange(i, 1) withString:#"_"];
// You should not replace a unmatched character with a _ . Because already matched letters would be overwritten.
}
hiddenTextField = theRiddle;
}
I assumed that the content of hiddenText.text is #"______"
and the content of fullText.text is #"Kartoffelkäfer". So hiddentext is the exact length as the fullText.
What I had to change to get this to work:
NSString *theRiddle;
NSString *hiddenTextField = [[[NSMutableString alloc] initWithString:hiddenText.text] autorelease];
for (int i = textCount-1 ; i>=0; i--) {
NSString *aChar=[fullTextField substringWithRange:NSMakeRange(i,1)];
if ([aChar isEqualToString:#" "]) {
theRiddle= [hiddenTextField stringByReplacingCharactersInRange:NSMakeRange(i, 1) withString:#" "];
}else if ([aChar isEqualToString:character]) {
theRiddle =[hiddenTextField stringByReplacingCharactersInRange:NSMakeRange(i, 1) withString:aChar];
}
else {
theRiddle = hiddenTextField;
}
hiddenTextField = theRiddle;
}
hiddenText.text=theRiddle;
Far away from good code, but I tried to change your code as little as possible.