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

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;
}

Related

Set text(with emojis, special chars, links) in UILabel, and link should be clickable

In one of my application, there is API called and get data from server. In that there is text - which contains emojis, special characters, URLs, etc.
Not In my UITableViewCell, I have Simple UILabel and set text to label.
Till now everything is working fine.
But now I want that URLs in UILabel should be tappable, so when we click on URL and it should be open in Safari.
Note : As text is coming from server, so I don't know position of URL and there will be multiple URL as well.
What to do for that ? I have searched but didn't find solution.
I needed this kind of linked text for another project last month. I created a custom UITableViewCell with a UITextView object in the cell, subclassed to a custom UITextView subclass. I just made a quick demo project and put it up on git for you now. Feel free to use it.
github.com/fareast555/MPC_LinkedTextView
The basic secret sauce for using text links is the NSLinkAttributeName attribute in the mutable text, and telling the system to handle links.
- (void)updateTextViewWithFullText:(NSString *)fullText linkTriggerText:(NSString *)triggerText linkURLString:(NSString *)urlString
{
//Create a mutable string based on the full text
NSMutableAttributedString *mutableString = [[NSMutableAttributedString alloc]initWithString:fullText attributes:nil];
//Add the link attribute across the range of the target text
[mutableString addAttribute:NSLinkAttributeName value:urlString range:[fullText rangeOfString:triggerText]];
//Add any other font or color bling as needed
[mutableString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:18 weight:UIFontWeightMedium] range:NSMakeRange(0, [fullText length])];
//Set the mutable text to the textfield
[self setAttributedText: mutableString];
}
#pragma mark - UITextViewDelegate
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction
{
return YES;
}
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
return NO;
}
And for textviews, you'll find it easier to use auto layout if you turn off scrolling.
#pragma mark - Configure
- (void)_configureTextView
{
self.delegate = self;
[self setEditable:NO];
[self setSelectable:YES];
[self setScrollEnabled:NO];
[self setUserInteractionEnabled:YES];
[self setDataDetectorTypes:UIDataDetectorTypeLink];
self.scrollIndicatorInsets = UIEdgeInsetsZero;
}

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;
}

Restrict the user to enter max 50 words in UITextView iOS

I am trying to restrict the user to enter max 50 words in UITextView. I tried solution by PengOne from this question1 . This works for me except user can enter unlimited chars in the last word.
So I thought of using regular expression. I am using the regular expression given by
VonC in this question2. But this does not allow me enter special symbols like , " # in the text view.
In my app , user can enter anything in the UITextView or just copy-paste from web page , notes , email etc.
Can anybody know any alternate solution for this ?
Thanks in advance.
This code should work for you.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
return textView.text.length + (text.length - range.length) <= 50;
}
Do as suggested in "question2", but add # within the brackets so that you can enter that as well. May need to escape it if anything treats it as a special character.
You use [NSCharacterSet whitespaceCharacterSet] to calculate word.
- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
static const NSUInteger MAX_NUMBER_OF_LINES_ALLOWED = 3;
NSMutableString *t = [NSMutableString stringWithString: self.textView.text];
[t replaceCharactersInRange: range withString: text];
NSUInteger numberOfLines = 0;
for (NSUInteger i = 0; i < t.length; i++) {
if ([[NSCharacterSet whitespaceCharacterSet] characterIsMember: [t characterAtIndex: i]]) {
numberOfWord++;
}
}
return (numberOfWord < 50);
}
The method textViewDidChangeSelection: is called when a section of text is selected or the selection is changed, such as when copying or pasting a section of text.

Add \n to NSString or searching lines position in UITextView

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;
}

Resources