Go to particular line in UITextView - iphone

How can I tell UITextView to set the cursor to a particular line (line 13, for example) when it appears?

UITextView has a method setSelectedRange: (NSRange) range.
If you know where in the string line 13 occurs, say location 237, then do: [textView setSelectedRange: NSMakeRange(237,0)];
If you need to find out where line 13 occurs, you've more work ahead. I'd start by looking at sizeWithFont, remembering to nip about 16 points off the width of your textView so that iOS gets the sums right. (That said, if you have line breaks, then just find the location of the 13th (or nth) "\n".)
Update following your further query in the comment
There are lots of ways of finding the position of the nth \n. The following snippet isn't pretty, but it will do the job. You could also use rangeOfString and iterate through the "\n". In this snippet, if the target line is greater than the number of lines, it puts the cursor at the end. The code here assumes you have a UITextView property called userEntry.
int targetLine = 3; // change this as appropriate 0=first line
NSRange range;
NSString* exampleString = #"Hello there\nHow is it going?\nAre you looking for a new line?\nA new line in what?\nThat remains to be seen";
NSArray* separateLines = [exampleString componentsSeparatedByString:#"\n"];
if (targetLine < [separateLines count])
{
int count = 0;
for (int i=0; i<targetLine; i++)
{
count = count + [[separateLines objectAtIndex:i] length] + 1; // add 1 to compensate \n separator
}
range = NSMakeRange(count, 0);
}
else
{
range = NSMakeRange([exampleString length], 0); // set to the very end if targetLine is > number of lines
}
[[self userEntry] setText: exampleString];
[[self userEntry] setSelectedRange:range];
[[self userEntry] becomeFirstResponder];

Related

Know where a UILabel splits a string when its multi-line property is on

Have a problem, need to assign some text to a UIButton's title. Have set the buttons line break mode to NSLineBreakByCharWrapping so that the string is separated only by characters at end of each line. But i need to insert an hyphen at the end of the line to show continuity of the word.
Heres what i tried -
// Initialize the button
titleButton.titleLabel.lineBreakMode = NSLineBreakByCharWrapping;
titleButton.titleLabel.backgroundColor = [UIColor yellowColor];
[titleButton.titleLabel setFont:[UIFont fontWithName:#"Helvetica-Bold" size:15]];
// Make the string here
NSMutableString *titleString = [[NSMutableString alloc] initWithString:#"abcdefghijklmnopqrs tuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"];
// Insert hyphens
int titleLength = [titleString length];
int hyphenIndex = 19;
while (hyphenIndex<titleLength) {
UniChar charatIndex = [titleString characterAtIndex:hyphenIndex];
if ((charatIndex - ' ') != 0) { // Check if its not a break bw two words
[titleString insertString:#"-" atIndex:hyphenIndex]; // else insert an hyphen to indicate word continuity
}
hyphenIndex += 19; //Since exactly 20 char are shown in single line of the button's label.
}
//Set the hyphenated title for the button
[titleButton setTitle:titleString forState:UIControlStateNormal];
[titleString release];
This is the closest i could get.
Any help would be greatly appreciated.
Try NSAttributedString
It give a great possibilities for working with strings.
WWDC 2012-230
For example:
- (NSUInteger)lineBreakBeforeIndex:(NSUInteger)index withinRange:(NSRange)aRange
//Returns the appropriate line break when the character at the index won’t fit on the same line as the character at the beginning of the range.
your second word's length is more the length of line (width of button) thats why this happen.
pasting hyphens is not very good idea. You should split your string on parts with size that fits button's width by using than add hyphens if needed
[String sizeWithFont:font constrainedToSize:Size lineBreakMode:LineBreakMode]
The main idea is to get portion of initial string (add hyphen if word breaks), check if its width fits button's width. If width is smaller, try bigger part, else if fits -- process further part
See my answer here for how to use NSParagraphStyle and NSAttributedString to get a UILabel that breaks with hyphens: https://stackoverflow.com/a/19414663/196358

Based on number of lines in uitextview getting substring

Frrom UITextview i am able to get number of lines for given text, if its more than 4 lines i want to truncate the rest, so how to get the index to substring?
It will restrict to user to enter more than 4 lines in a UITextview
- (BOOL)textView:(UITextView *)aTextView shouldChangeTextInRange:(NSRange)aRange replacementText:(NSString*)aText
{
if (textView.contentSize.height/textView.font.lineHeight>4) {
return NO;
}
else
return YES;
}
NSMutableString *str = [[NSMutableString alloc] initWithString:textView.text];
static int numberOfLines = 0;
int nOC = 1;
while (nOC < [textView.text count] && numberOfLines < 4) {
if ([[str substringWithRange:NSMakeRange(nOC,1)] isEqualToString:#"\n"]; ) {
numberOfLines++;
}
nOC++;
}
NSString *finalString = [str substringWithRange:NSMakeRange(1,nOC)];
i hope this should work out for u. i calculated the number of characters till the 4th "\n" and used substringWithRange to extract the desired string. i didnt try this piece of code but this logic should work or at least assist u in your code. happy coding :)

Appending UIButton with NSString

I have this code to show some text in a textview from SQLite DB..
NSMutableString *combined = [NSMutableString string];
for(NSUInteger idx = 0; idx < [delegate.allSelectedVerseEnglish count]; idx++) {
[combined appendFormat:#" %d %#", idx, [delegate.allSelectedVerseEnglish objectAtIndex:idx]];
}
self.multiPageView.text = combined;
self.multiPageView.font = [UIFont fontWithName:#"Georgia" size:self.fontSize];
delegate.allSelectedVerseEnglish is the NSArray
multiPageView is the UITextView
i put the above loop function to get the Numbers according to the text,for example 1 hello 2 iPhone 3 iPad 4 mac etc etc..i just want UIButton between the text instead of 1 2 3 4 ..for example i want unbutton hello unbutton iPhone etc etc.because i need to make some touch events from it.how to do this?
Thanks in advance.
If you want to place UIButtons between some text in textview, there is no other way but to place it as a separate view just above. So you'll need to add spaces beneath those buttons, the amount of those you should calculate yourself, based on the size of your buttons.
So, if you would like yo see something like this:
Press here [UIButton] or here [Another UIButton],
your text string should look like this
Press here or here ,
So when you add the buttons on those places, it would look just like you wish.
UPDATE
Seems like we need some more code here, so here it is:
First, you'll need to calculate the size of a letter. Let's assume that it is 10 pixels height and 8 pixels.No, let's just call that letterHeight and letterWidth.Let's also assume that you want 64x10 pixels buttons. So, we will need 64/8=8 +2 spaces to out behind that button(2 to make borders around that)
So, here we go
NSMutableString *combined = [NSMutableString string];
int letterHeight = 10;
int letterWidth = 8;
for(NSString *verse in delegate.allSelectedVerseEnglish) {
[combined appendFormat:#" %#",verse];//10 spaces there
//You have to experiment with this, but idea is that your x coordinate is just proportional to the length of the line you are inserting your button in, and y is proportional to number of lines
int xCoordinate = [combined length]*letterWidth%(int)(self.multiPageView.frame.size.width);
int yCoordinate = [combined length]*letterWidth/(int)(self.multiPageView.frame.size.width)*letterHeight;
UIButton *newButton = [[UIButton alloc]initWithFrame:CGRectMake(xCoordinate,yCoordinate,64,10)];
[self.multiPageView addSubview:newButton];
}
self.multiPageView.text = combined;

How to know the displayed text in UILabel?

I have an UIView containing two UILabels, in order to display a string.
The first UILabel has a fixed size, and if the string is too long and can't hold in this UILabel, I want to display the maximum characters I can in the first UILabel, and display the rest of the string in the second UILabel.
But to make this, I must know the exact part of the string displayed in the first UILabel, which is not easy because of the randomness of the string and the linebreaks.
So, is there a way to get just the text displayed in the first UILabel, without the truncated part of the string?
if ([_infoMedia.description length] > 270) {
NSRange labelLimit = [_infoMedia.description rangeOfString:#" " options:NSCaseInsensitiveSearch range:NSMakeRange(270, (_infoMedia.description.length - 270))];
_descTop.text = [_infoMedia.description substringToIndex:labelLimit.location];
_descBottom.text = [_infoMedia.description substringFromIndex:(labelLimit.location+1)];
} else {
_descTop.text = _infoMedia.description;
_descBottom.text = #"";
}
Okay that's a late answer but maybe it could help someone. The code above is approximatively the solution I used in my app.
_descTop is my first label and _descBottom is the second label. 270 is a constant equivalent to a little less than the average maximum number of characters displayed in my first label, _descTop. I calculated it by hand, trying with many different strings, maybe there's a better way to do that but this worked not bad.
If the string I want to display (_infoMedia.description) is larger than 270 characters, I isolate the first 270 characters plus the end of the next word in the string (by searching the next space), in the case where the 270 characters limit would cut the string in the middle of a word. Then I put the first part of the string in my first label, and the second part in the second label.
If not, I only put the globality of the string in the first label.
I know that's a crappy solution, but it worked and I didn't found any better way to do that.
Following code might help you in getting what you want!!
//If you want the string displayed in any given rect, use the following code..
#implementation NSString (displayedString)
//font- font of the text to be displayed
//size - Size in which we are displaying the text
-(NSString *) displayedString:(CGSize)size font:(UIFont *)font
{
NSString *written = #"";
int i = 0;
int currentWidth = 0;
NSString *nextSetOfString = #"";
while (1)
{
NSRange range;
range.location = i;
range.length = 1;
NSString *nextChar = [self substringWithRange:range];
nextSetOfString = [nextSetOfString stringByAppendingString:nextChar];
CGSize requiredSize = [nextSetOfString sizeWithFont:font constrainedToSize:CGSizeMake(NSIntegerMax, NSIntegerMax)];
currentWidth = requiredSize.width;
if(size.width >= currentWidth && size.height >= requiredSize.height)
{
written = [written stringByAppendingString:nextChar];
}
else
{
break;
}
i++;
}
return written;
}
#end

Reuse Cocos2d CocosNodes

I am trying to create a cool score counter in my iPhone game, where I created the digits 0 to 9 in photoshop and I want to update the score every second.
What I am doing now is the following:
In my init I load all the digit sprites into an array, so that the array has 10 items.
I created a method which breaks down the current score (eg. 2000) into single digits and gets the sprites from the array and after that adds them to a parent CocosNode* object.
Every second I get the parent CocosNode by it's tag and replace it with the new parent object.
Currently I am already running into problems with this, because the score 2000 uses the 0-digit three times and I cannot re-use sprites.
- (CocosNode*) createScoreString:(int) score
{
NSLog(#"Creating score string : %d", score);
NSString* scoreString = [NSString stringWithFormat:#"%d", score];
int xAxes = 0;
CocosNode* parentNode = [[Sprite alloc] init];
for (NSInteger index = 0; index < [scoreString length]; index++)
{
NSRange range;
range.length = 1;
range.location = index;
NSString* digit = [scoreString substringWithRange:range];
Sprite* digitSpriteOriginal = [self.digitArray objectAtIndex:[digit intValue]];
Sprite* digitSprite = [digitSpriteOriginal copy];
[digitSprite setPosition:cpv(xAxes, 0)];
xAxes += [digitSprite contentSize].width - 10;
[parentNode addChild:digitSprite];
}
return parentNode;
}
Am I handling this the right way within cocos2d or is there some standard functionality for this? Also, if this is correct, how can I 'reuse' the sprites?
I believe that you want to use the LabelAtlas class, you'll only need to provide a compatible bitmap (like one the fps counter uses).