How to extract sub-string from UILabel based on finger pressed location? - ios

I have a UILabel which contains text.
Once I press on this UILabel, I want to extract one word from the location where my finger pressed.
I've searched a bit on internet, but have no clue about how to implement it.
Does anyone here know how to do it?
Thanks in advance.

Once I press on this UILabel, I want to extract one word from the
location where my finger pressed.
That's not something that's going to be easy to do with UILabel. UILabel is meant to be a simple way to put static text on the screen; it doesn't provide features that would let you determine the frames of individual words.
You'll probably be better off creating your own view for this. You'll want to dig into Core Text to lay out and draw the text. Core Text is a lot more complicated than just using a simple UILabel, but it gives you the information and control you'll need to determine where each word is drawn on the screen. Your view can use that information to map touches to words.

The easiest way is to just make each individual word a separate label, so that all you have to do is add a UITapGestureRecognizer to the label and grab the text from it when it's touched.
If you want to do it with one label, though, here's some pseudocode of a way that could work:
Add a UITapGestureRecognizer to the label. When touched, get the location of the touch.
Use NSString's - (CGSize)sizeWithFont:(UIFont *)font method to get the size of the label's entire string (let's call this stringSize).
Compare stringSize.width to the width of your label to figure out where the text begins (if your label is center or right aligned, this might not be at the label's starting X coordinates). ie. startingX = label.width - stringSize.width / 2.
Now use NSString's - (NSArray *)componentsSeparatedByString:(NSString *)separator method to separate the string in your label into each word, with the space character as the delimiter. Let's store this into an array called wordsAr.
Create a variable, currentXPos, and initialize it to startingX.
Now create a for loop that goes through each word in wordsAr, calculates the size of that word using - (CGSize)sizeWithFont:(UIFont *)font, and adds it to currentXPos. When currentXPos >= the x location of your touch value, you've found the word that you tapped on.

You can use TTTAttributedLabel in the following link: https://github.com/mattt/TTTAttributedLabel
Define your clickable texts as Links for the Label, then you'll get exactly what you need.

Related

Adding UITextField inline UILabel (Fill in the blanks)

I am trying to achieve something like this for iOS in Objective C.
The fill in the blanks(UITextField) should be inline, and should be able to have its own inputType.
Also, each View is a type of cell.contentView of a UITableViewCell.
My current approach is to find the length of string and also calculate the wrapping content length to the next line. Calculate the x's and y's for UITextField and add another UILabel after the UTextField
Is there any other approach other than this?
As EmilioPelaez says, this is not exactly an answer to your question, but a suggestion:
You can use a collection view with an horizontal flow for each "sequence" (i.e. UILabel-UItextfield-etc...)
That collection view has 2 kind of cell:
One with a uilabel with the number of line set to "1"
and the correct layout to fit the cell.
Another with a uitextfield and the correct layout
Coupled with:
My current approach is to find the length of string and also calculate the wrapping content length to the next line.
You may be able to easily adjust the width of the different cells, hide a uitextfield (if needed) and display a more dynamic "sequence" (if needed)
This is not exactly an answer to your question, instead it's a suggestion for a different interaction.
I think that instead of using inline textFields, you could use a UILabel with an attributed string, and in where the textFields would be, you add a different character with a different color that you can tap (For example, this character ✚).
When tapped, you can show an overlay with a text input, and once that input is completed, you update the label with the text (still tappable, and with a different color).
I think this answer might also be relevant: Detecting taps on attributed text in a UITextView in iOS
I think your solution of separating the UILabels and calculating their required positions is a good one for versions lower than iOS9, but if you can count on iOS, UIStackView can dramatically simplify the process for you. You can read more about the process in this tutorial:
UIStackView Tutorial
Good luck!

Making some parts of a `UITextField` un-selectable

I have a UITextField that will represent an integer number with a fraction (numerator and denominator). As an example: "27 3/16". I want to make the denominator "/16" at the end both un-editable and also un-selectable.
I can use the delegate method textField:shouldChangeCharactersInRange:replacementString: to prevent the "/16?" from being edited with an approach a bit like this.
Is there some way that I can also prevent the "/16" from being selectable at all? So, the caret can't be moved in to it, and the selection marque can't be made around it.
If this isn't possible, is there a hook so that once the user finishes placing their selection, I can update the selection and move the caret to just before this piece of the text.
Thanks.
You can have a UILabel and UITextField constrained via autolayout next to each other, the UILabel containing the denumerator and the UITextField the numerator.
Here is an answered question for how to do that: Using Auto Layout to have UILabel and UITextField next to each other (the essence is, you need to adjust the content hugging priority of the UITextField to make it always as wide as the contained text.
If your text field gets too small to be tapped, you can apply the code of this answer to a UITextView and make the tappable area of your view bigger: UIButton: Making the hit area larger than the default hit area (but better use method swizzling than overriding a method in a category like in the answer! Or a subclass.)

UITextview not getting completely filled with the text in IPhone

In my app, I have a UITextView. When I key in data in the UITextView, the words are not getting completely filled in the UITextview. There is a boundary within the UITextView and the words scroll up as I key in the words. Is there a setting which I am missing in UITextView. Please let me know. Please find the screenshot below
You can set a frame and a contentSize as it inherits from the UIScrollView to make it bigger. I do not have access to IDE right now but something like this should work:
myTextView.frame = CGRectMake(10,10,300,300);//example values
myTextView.contentSize = CGSizeMake(300,300);//example values
but sooner or later you want be able to see the whole text on the screen and you will need to scroll anyway.
You can also change this values while user is typing by using some delegate methods

Adding background image to the selected in an UITextView

I would like to add a background image for the selected text in the UITextView, not for the whole view, as I marked in the below picture.
How can I add a background image for the selected text?
Or, how can I add one small image before and another one after the
selected without making the other text move back or forward?
UITextInput protocol should provide everything you need.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInput_Protocol/Reference/Reference.html
Specifically:
selectedTextRange
firstRectForRange
firstRectForRange: which will tell you the rectangle covering a range of characters. If the range of characters spans multiple lines, you have to call it repeatedly. The first time it will give you the first rect and tell you what range that covers. Then, you adjust the range you're asking about to be the remaining characters you're interested in and repeat.

Add UIGestureRecognizer to individual letters of UILabel

Right Now I am making an iOS app and I would like to implement the ability to remove letters in a UILabel by simply "Dropping the letter". The part That I am having an issue with is adding a gesture recognizer to individual letters of a UILabel. I have already searched the web for this and have nothing.Just to be clear, I am NOT adding a gesture recognizer to the whole label, I am only wanting to add it to individual letters. Any help is greatly appreciated.
Thanks
It seems that the easiest way to do it is by dynamically calculating the position of a letter. Use this:
CGSize textSize = [text sizeWithFont:[UIFont boldSystemFontOfSize:size]
constrainedToSize:constrainedSize
lineBreakMode:NSLineBreakByWordWrapping];
so you can get the the size for a letter in the font and size you are using for each label and using the [stringInstance length] property and the [UILabel numberOfLines] property to get the approximate center for each letter in a label, then use a simple tapGestureRecognizer for each label and in there calling your method for
- (NSString*)letterForPoint:(CGPoint)tapCenter inLabel:(UILabel*)label;
there you use everything to calculate the approximate center for each letter and adding a selectableRange for error and correct user responding as x +- 20 pixels and y +- 20 pixels.
Apple says that anything with a selectable bound lesser than 40 pixels for 40 pixels will be completely annoying for the user, so your font size should actually be quite big for user interaction.
If I am understanding correctly, it sounds like subclassing UILabel would make sense.
Make a LetterLabel: UILabel class
and in the init set up your GestureRecognizer on self.
Then when you create your letters each one will have the recognizer attached to it
LetterLabel *firstLetter = [[LetterLabel alloc] init]
LetterLabel *secondLetter = [[LetterLabel alloc] init]
UIGestureRecognizer can only be applied to a UIView or subclass of that (e.g. a UILabel, like Adam suggested). If you are worried about performance, then I think your next step would be to:
1) Subclass UIView in order to create a custom implementation of a UILabel-like view.
2) Draw out the custom label's string to in the drawInRect: method
3) Use the touchesBegan:withEvent:, touchesMoved:withEvent:, and touchesEnded:withEvent: methods to track finger positions in order to move/redraw characters of the backing string.
EDIT:
Alternatively, you could use one UIPanGestureRecognizer on a the custom label to track finger positions, and move around sublayers within the bounds of the custom label (each sublayer could contain a character in the string). In this way, you could more easily take advantage of Core Animation to animate the characters (i.e. create the "dropping" effect).

Resources