How to implement search function to UITextView? - ios

I have more than 40 views with their own respective UITexView. I want to implement a search function that allows the user to search across the UITextViews. Actually, I do not even know how to implement search function for 1 UITextView. Therefore I do not know if it is possible at all.
I have searched the web and looked for it here but did not find what I looked for.
I appreciate your advice.

This is a pretty easy (may I say obvious?) task. Just think a bit about it. What does searching in a text view mean? Well, it means getting its text and see if a particular string (the one which is searched for) is the substring of the text, and if so, where it is inside. Assuming you use a UISearchBar to hold the text to be searched for:
NSString *subs = searchBar.text;
NSString *wholeText = textView.text;
NSRange r = [wholeText rangeOfString:subs];
if (r.location == NSNotFound)
{
// The term to be searched couldn't be found...
}
else
{
// The string to be searched for is in the text view, r.location contains where exactly it is.
}

You can search for text in TextView like this:
[TextView.text rangeOfString:]
There's no built in controller for searching UITextView, you have to implement this functionality by yourself with above function.

Related

Make text matched with NSRegularExpression clickable in UITextView

I have a UITextView and using NSRegularExpression. I'm finding names in my text view. So I'm able to highlight matches using this code:
for match in matches as [NSTextCheckingResult] {
let matchRange = match.range
attributedText.addAttribute(NSStrokeColorAttributeName, value: UIColor.blueColor(), range: matchRange)
}
I want to make it clickable and pass its text to a new view controller. Or maybe change it to a UIButton with the same text and add a segue to the new view controller. I'm not sure how to do it correctly.
UITextView doesn't really have functionality for that. You could try your UIButton approach but you'll have trouble with links that wrap on multiple lines.
Two possible solutions:
You may be able to force its URL handling functionality to do what you want - see this question. This will depend on your NSRegularExpression.
You might want to try replacing your text view with TTTAttributedLabel or a similar third-party library that handles this for you. I think this is the most flexible option, and my recommended approach.
For future googlers, you could use NSLinkAttributeName
attributedText.addAttribute(NSLinkAttributeName, value: "\(your_value)", range: matchRange)

how to set a clickable URL in UILabel? [duplicate]

I have a UILabel whose text I am getting from a server. Some of the text is to be identified as links, and on touching those links some action should be performed. e.g.
NSString *str = #"My phone number is 645-345-2345 and my address is xyz";
This is the complete text for UILabel. I have only one UILabel for displaying this text (Text is dynamic. I just gave an example.). On clicking these links I need to perform actions like navigating to some different screen or make a call.
I know that I can display such text with help of OHAttributedLabel. And the links can be displayed as follows :
[label1 addCustomLink:[NSURL URLWithString:#"http://www.foodreporter.net"] inRange:[txt rangeOfString:someString]];
But I wonder how can I make these text links perform some action like navigation to different screen or making a call.
Let me know if more explanation is required.
You can add custom actions to any of the available UILabel replacements that support links using a fake URL scheme that you'll intercept later:
TTTAttributedLabel *tttLabel = <# create the label here #>;
NSString *labelText = #"Lost? Learn more.";
tttLabel.text = labelText;
NSRange r = [labelText rangeOfString:#"Learn more"];
[tttLabel addLinkToURL:[NSURL URLWithString:#"action://show-help"] withRange:r];
Then, in your TTTAttributedLabelDelegate:
- (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url {
if ([[url scheme] hasPrefix:#"action"]) {
if ([[url host] hasPrefix:#"show-help"]) {
/* load help screen */
} else if ([[url host] hasPrefix:#"show-settings"]) {
/* load settings screen */
}
} else {
/* deal with http links here */
}
}
TTTAttributedLabel is a fork of OHAttributedLabel.
If you want a more complex approach, have a look to Nimbus Attributed Label. It support custom links out-of-the-box.
You can use UITextView with Phone numbers and links detection YES, scrolling disabled YES user interaction enabled YES, instead of UILabel.
My project has successfully used OHAttributedLabel for this. Check out the
-(BOOL)attributedLabel:(OHAttributedLabel*)attributedLabel shouldFollowLink:(NSTextCheckingResult*)linkInfo;
method in OHAttributedLabelDelegate (link). It allows you to decide what happens when a link is clicked. If you look at the source for the example from the OHAttributedLabel project, it's used to display an alert. If you returned NO in this case (to keep the default action from happening too), you could just do whatever you wanted like navigation, etc.
Note however that this requires that you can determine the action correctly just from the text. For our project, we used a slightly fancier solution, where the server sent us text with tags in them and a list of commands to perform for each tag.
There a project called FancyLabel that is about what you need. It might need some customization though.
Also, I think Three20 has this functionality, but it might be an overkill if you don't already use it.
There's also a much simpler solution, if all of your links are phones \ addresses \ urls. You can simply use a UITextView instead of a UILabel. It has auto detection of phones, address, etc. (just check the boxes in IB)
You can also have custom actions in response to click events on those links by overriding openURL, as explained here
Is there a specific reason that you must use a UILabel instead of a UITextView?
Note that a lot of the implementations of attributed labels inherit from UIView or don't implement all of UILabel's functionality.
You can use custom button to give a look like of link ..Also you can add gesture on the custom label if you dont want to use button ..
UITapGestureRecognizer* gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(userTappedOnLink:)];
// if labelView is not set userInteractionEnabled, you must do so
[labelView setUserInteractionEnabled:YES];
[labelView addGestureRecognizer:gesture];
I'm not a fan of being forced to use UITextView or a third party lib when all I need is a lightweight label that renders links (and that tells me when they're tapped!)
Here's my attempt at a lightweight UILabel subclass able to detect link taps. The approach is different from others I've seen in that it gains access to the UILabel's shared NSLayoutManager via a delegate callback added to NSTextStorage via a category extension. The beauty is that UILabel performs its native layout and drawing - other UILabel replacements often augment or replace the native behavior with an additional NSLayoutManager/NSTextContainer.
Probably App Store safe, but somewhat fragile - use at your own risk!
https://github.com/TomSwift/TSLabel

How to Create Dynamic String Object

In my Application, I need to save a UITextView's text in NSAttributedString.
When a user swipes on the screen then whole text in UITextView will copy in NSAttributedString and UITextView will become NIL and then after some writing in UITextView if User will do again Swipe then that Text will also store in another NSAttributedString.
My problem is, I don't know how many times User will do swipe.
So, i have to take as many string as many times User will do swipe on screen.
I need to take something Like this
For Example...
Int var = 5;
NSAttributedString *strObject(var);
So, actually NSAttributedString object is strObject5
"OR" May be Like This...
for(Int i=0;i<=var;i++)
{
NSAttributedString *strObject(var);
}
I knew that, this all things are wrong but i need to do something like this.
Any idea, link, code, tutorial will be great Help.....

iOS Instagram Tags Text Layout? How Is It Done?

I've always been curious how instagram gets it's tags to layout fluidly and wanted to know what goes behind this functionality? To me, it seems like they're using UIButton's and just calculating placement of the buttons line by line? Is that right? Or is there a simpler method of doing it without having to manual calculate the placement of each tag line by line / or side by side given that multiple tag's width's fit together?
Or, are they using NSAttributedStrings?
Any ideas?
Here's an example of the layout I'm referring to.
Well, I'm currently working on NSAttributedString and UITextView to get all this working, and my current code can do it. So I'm going to explain a possible version of doing this.
Here are the tips and big steps, with iOS7:
NSAttributedString, in iOS7 has a new attribute : NSLinkAttributeName. You can add it to your NSAttributedString, and with a detection method (combining: how to make #key and #key clickable in IOS7 and Get word from tap in UITextView) you can manage it. That's for the general way of doing it. For previous version, you'll have to do a little more of work, but keeping this general idea.
But since, it only for hashtags, since you can detect the world behind the tap, you can do this: Detect what word has been tapped (see previous links), detect if this word has an hashtag, and if yes, you can do whatever action you want. You can play with a NSRegularExpression to know where are the hashtags, and know when to "color" them.
Here is a simplified way to do it using UITextView and NSAttributedString:
Use regular expressions to get character ranges for links.
Add link styling to the matched ranges.
Add custom attribute to range that references tap action to execute.
On touch, if index of character is inside a matched range, change the link formatting to highlight it and run the associated tap action.
How to get index of character at location in iOS7:
- (NSUInteger) getCharIndexAt: (CGPoint) location
{
NSLayoutManager *layoutManager = self.layoutManager;
NSUInteger characterIndex = NSNotFound;
characterIndex = [layoutManager characterIndexForPoint:location inTextContainer:self.textContainer fractionOfDistanceBetweenInsertionPoints:NULL];
return characterIndex;
}
Also check out WWDC 2013 intro to TextKit Demo
ios7 text utilities

How to push key value into UITextView from custom keyboard in iOS

I am building a virtual keyboard for a UITextView. All works well, I can display the keyboard and remove the keyboard as well as display the keystrokes. I am using the "stringByReplacingCharactersInRange: withString" method to place the new keystroke into the text view. This works but since it is replacing the string each time, the entry point goes to the end of the string. This all makes sense, but is not very usable. I can fix this by doing checks in my code but there might be something better...
So my question is this; Is there a way to push the new key to the UITextView directly without modifying the UITextView's text property's string manually? The manual states that I will have to manage the target/action myself, but I was wondering if I've missed an action to call. It seems that the Apple Default keyboard must have a slick way of punching the keystroke into the object without the obvious number of checks that I will have to do to make the typing smooth.
Any help will be greatly appreciated.
Thanks,
Rob
Well, I didn't get any responses. So I figured out a way to do it so it is reasonable and simple. It's a matter of tracking the selected range. So when I wish to Backspace I use this technique.
NSRange currentRange = self.myTextView.selectedRange;
if (currentRange.length == 0) {
currentRange.location--;
currentRange.length++;
}
self.myTextView.text = [self.myTextView.text stringByReplacingCharactersInRange:currentRange withString:[NSString string]];
currentRange.length = 0;
self.myTextView.selectedRange = currentRange;
If I need to type a character this works.
NSRange currentRange = self.myTextView.selectedRange;
self.myTextView.text = [self.myTextView.text stringByReplacingCharactersInRange:currentRange withString:someCharacter];
currentRange.location++;
currentRange.length = 0;
self.myTextView.selectedRange = currentRange;
If anyone has a better way, I'd like to hear it.
Thanks,
Rob

Resources