Add \n to NSString or searching lines position in UITextView - ios

I have plain NSString which i put into UITextView . I need to search position when new line starts. I think it can be done if textview converts string from
#"This is a big test string which i want to put into UITextView" to #"This is a\n big test \nstring which\n i want to\n put into\n UITextView" automaticaly. Then i can search for "\n" and find position of some line . Any idea how can i do it ?

That's not the way how UITextView works. The process of laying out text in a container is more complicated than just finding line breaks and does not produce a new string containing NL characters.
On iOS 7 you could use the TextKit properties (layoutManager, textContainer, ...) of UITextView to access the underlying layout components and query them for positions of parts of your string.
If you have to support older iOS versions there's characterRangeByExtendingPosition:inDirection: in the UITextInput protocol. You can use it to calculate the extent of a line of text.

I count "\n"s in an app to know when to hide the keyboard. instead of counting \ns you can count the other chars to get your "\n" location. Rows just counts the number of "\n"s, and is reset to zero on view did load.
// dismiss keyboard from text view with return key
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if([text isEqualToString:#"\n"]) {
rows++;
if ( rows >= 2 ){
// resign text view
[self.quotationTextView resignFirstResponder];
return NO;
}else{
return YES;
}
}else{
rows = 0;
}
return YES;
}

Related

Building a facebook messenger style new message friend addition - uitextfield / uitextview

I'm trying to make a fb messenger style new message formation uitextview.. as shown in the image..
Specifically, how to make the uitextview which is at the top of the tableview (showing list of selected friends). I want to make a uitextview with the following properties..
1) It expands/contracts as more names are added/removed to/from it.
2) The textview is editable - but not partially editable, i.e., a name is either wiped out by backspace or not (like how it happens in fb)
3) Possibly this editing happens in nice aesthetics (similar to fb, make the color of the entire text blue colored before backspacing it out)
It has been a while since I have used objective-c, but I believe this is correct. It may not be though. And yes I would eventually switch to swift.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
//you should have an array of names as a property, not here.
NSMutableArray* nameArray = [#"sam"];
if ([text isEqual: #""]) {// this is delete
for (NSString *name in nameArray) {
NSRange nameRange = [textView.text rangeOfString:name];
if (nameRange.location == range.location) {
textView.text = [textView.text stringByReplacingCharactersInRange:nameRange withString:#""];
[nameArray removeObject:name]
return false;
}
}
}
return true;
}

How to get n lines of text from UITextView in iOS

In my application i need to restrict to user enter 7 lines only in UITextView. When he tries enter text in 8 line we need to stop allowing editing and show an alert message. Its working fine by using CGSize of getting UITextView text.
But when user enters text in UITextView as Paste its not allowing if text is more than 7 lines. As per requirement i need to get the 7 lines of Text from entred (Copied & Pasted ) in to UITextView.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)string
{
NSString *temp = [textView.text stringByReplacingCharactersInRange:range withString:string]
CGSize size = [temp sizeWithFont:textView.font constrainedToSize:CGSizeMake(textView.frame.size.width,999) lineBreakMode:UILineBreakModeWordWrap];
int numLines = size.height / textView.font.lineHeight;
if (numLines <= 8)
{
return true;
}
//Alert
return false;
}
Please help me in this issue.
Thanks in Advance.
You could use the UITextViewTextDidChangeNotification notification to alert you on other changes like text being pasted in. (referenced at the bottom of this page)
Or, there is also this handy category on UITextView that allows it to work with the UITextField UIControl events that can be found here.

textView:shouldChangeTextInRange:replacementText: returning NO, but autocorrect ignores?

I'm having the following problem, and am not sure if this is an iOS bug, or I'm misunderstanding UITextViewDelegate callbacks. I'm able to reproduce this behavior on my device (iPad retina) and on the simulator only if I use the software keyboard (i.e. use my mouse to click the on-screen keyboard).
Consider the following contrived example project (Updated 1/9/14):
https://www.dropbox.com/s/1q3vqfnsmmbhnuj/AutocorrectBug.zip
It's a simple UITextView, with a view controller set as its delegate, with the following delegate method:
- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if ([text isEqualToString:#" "]
&& range.length == 0
&& (range.location == 0
|| [[textView.text substringWithRange:NSMakeRange(range.location-1, 1)] isEqualToString:#"\n"])) {
textView.backgroundColor = [UIColor yellowColor];
return NO;
}
return YES;
}
My intention with this code is that when the user types a space (edit: and that space is the first character on the line), the space is ignored and instead some other functionality happens, in this case the UITextView turns yellow.
Now consider these steps:
Tap in the text view to make it first responder
Type "Apple", hit return and note the positioning
Now, type a space (turning the text view yellow), type "Apple" again and hit return.
Expected: A yellow background and text reading:
Apple
Apple
Observed: A yellow background and text reading (due to an autocorrection):
Apple
Apple
It appears the autocorrection logic is ignoring the result of textView:shouldChangeTextInRange:replacementText:.
Is this expected behavior?
If so can it be worked around?
Edit 1/9/14: only the first space on a line should be ignored, further spaces should be processed as normal (i.e. inserted into the text), ruling out a brute force strip of spaces. Also I'm dealing with a large string (potentially hundreds of thousands of characters) in a text editor (meaning constant user typing), so analyzing the entire string with every keystroke isn't going to be performant.
Yes, I see it too on my iPad 7.0.3 simulator.
One way to solve it is to add this UITextViewDelegate method:
- (void)textViewDidChange:(UITextView *)textView
{
// eliminates spaces, including those introduced by autocorrect
if ([textView.text rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet]].location != NSNotFound) {
textView.text = [textView.text stringByReplacingOccurrencesOfString:#" " withString:#""];
}
}
Update
It seems that this delegate method is called after autocorrection, just that the in the case you want to prevent (where "Apple" becomes " Apple") the replacement text is " Apple" and not " ". So to modify the implementation to prevent "\n " but allow other " " characters in your text, you could try comparing the first character of text to " " instead of comparing text to " ".
- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
// compare first character to 'space' character by decimal value
if (text.length && [text characterAtIndex:0] == 32) {
// check if previous character is a newline
NSInteger locationOfPreviousCharacter = range.location - 1;
if (locationOfPreviousCharacter < 0 || [textView.text characterAtIndex:locationOfPreviousCharacter] == 10) {
textView.backgroundColor = [UIColor yellowColor];
return NO;
}
}
return YES;
}

Text character location changed when UITextView has Under line text in iOS 6

In my app i am giving command to user to create Bold,Italic and UnderLine text.
Bold and Italic text is coming perfectly.
and also Underline text working Perfectly in iOS 7.
But When used that code in iOS 6 the Underline will come under the text but the next character will come on range.location=0.
I just want the text go smoothly with UnderLine Text when User type.
My code for UnderLine Text is
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSLog(#"shouldChangeTextInRange %d - %d - %d",range.location,range.length,txtViewOfNotes.attributedText.length);
if (range.location==0) {
NSLog(#"location 0");
}
else{
NSLog(#"location 123");
NSMutableAttributedString *mat = [txtViewOfNotes.attributedText mutableCopy];
[mat addAttributes:#{NSUnderlineStyleAttributeName: #(NSUnderlineStyleSingle)} range:NSMakeRange (mat.length-1, 1)];
txtViewOfNotes.attributedText = mat;
}
}
OutPut for Example:
e
n
i
l
I am typing now txtUnder
Any one know why this is happening in only iOS 6.
You should just update the [textView textStorage] attributes rather than making a copy of the attributed string and replacing it.
So get rid of the mutableCopy line of code and replace the next line with:
[[textView textStorage] addAttribute:...]
Your code is completely replacing the textView's attributed string and as a consequence the cursor position is being reset. No need to replace it, just add attributes to the existing textStorage (which is already a mutableAttributedString).
See here for more on formatting text and images in UITextView and NSTextView.

iOS: Appending an uneditable string to the end of a UITextView

I would like to reproduce a screen similar to the Facebook "Update Status" view in iOS.
(This text should be editable) Walking (Anything past here should not be editable) - at South Narrabeen Beach
The user should be able to enter/edit text to the left of the appended string. The appended string will need to wrap within its parent and be clickable.
Does anyone know how this is done? (I have recently seen it in the Viddy app as well).
Could it be a growing UITextField with a UIAttributedString split over 2 lines that updates its frame as the text is entered?
Update:
It looks like what you want is to let the user place the cursor in the signature anyway, but not let her type
In that case, you would want to use this instead
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
NSInteger signatureLength=20;
if(range.location>self.textView.text.length-signatureLength){
return false;
}
else{
return true;
}
}
Original:
You need to use UITextViewDelegate
Implement the - (void)textViewDidChangeSelection:(UITextView *)textView method, something like:
For this example, let's assume the signature length is 20, this would look something like this:
-(void)textViewDidChangeSelection:(UITextView *)textView{
NSInteger signatureLength=20;
NSRange newSelection=self.textView.selectedRange;
if(newSelection.location>self.textView.text.length-signatureLength){
[self.textView setSelectedRange:NSMakeRange(self.textView.text.length-signatureLength, 0)];
}
}
So basically you intercept every time the selection (== the cursor in this case) changes, and if the cursor is going to be in the middle of the signature, you reposition it just before.
Setting a selection with a 0 length just changes the cursor position.

Resources