I have implemented a UITextView where i can underline the text, sometime the text is not underlined at the right place it crosses the words and sentences, is there a default method which underlines the sentences at the right places avoiding the user to maintain the accuracy while touching the screen. help greatly appreciate please share your views.
I would use a UITextView with attributed text and modify the attributes as needed.
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:#"All work an no play makes Jack a dull boy."];
[attributedString addAttribute:NSUnderlineStyleAttributeName value:#(NSUnderlineStyleSingle) range:NSMakeRange(15, 4)];
self.textView.attributedText = attributedString;
where self.textView is an IBOutlet to your UITextView and the values are the NSRange are determined by your user interaction.
The problem is that internally a UITextView is a UIWebDocumentView (aka WebKit) and HTML has different rules for underlining words than normal text editors. See my analysis here: http://www.cocoanetics.com/2012/12/uitextview-caught-with-trousers-down/
The approach to set the attributedString the the problem that you would only be able to set the entire text.
Since we do not have direct access at the text container inside UIWebDocumentView and because of the intricacies of HTML you cannot hope to achieve a perfect result.
You can only solve this problem by rendering the text yourself with CoreText. My open source component DTCoreText could help with the display. I am also selling a commercial component for rich text editing that is based on that: http://www.cocoanetics.com/2012/12/dtrichtexteditor-1-1/
PS: he standard method for toggling the currently selected range of text underlined is toggleUnderline: defined as such:
#interface NSObject(UIResponderStandardEditActions) // these methods are not implemented in NSObject
- (void)cut:(id)sender NS_AVAILABLE_IOS(3_0);
- (void)copy:(id)sender NS_AVAILABLE_IOS(3_0);
- (void)paste:(id)sender NS_AVAILABLE_IOS(3_0);
- (void)select:(id)sender NS_AVAILABLE_IOS(3_0);
- (void)selectAll:(id)sender NS_AVAILABLE_IOS(3_0);
- (void)delete:(id)sender NS_AVAILABLE_IOS(3_2);
- (void)makeTextWritingDirectionLeftToRight:(id)sender NS_AVAILABLE_IOS(5_0);
- (void)makeTextWritingDirectionRightToLeft:(id)sender NS_AVAILABLE_IOS(5_0);
- (void)toggleBoldface:(id)sender NS_AVAILABLE_IOS(6_0);
- (void)toggleItalics:(id)sender NS_AVAILABLE_IOS(6_0);
- (void)toggleUnderline:(id)sender NS_AVAILABLE_IOS(6_0);
#end
This is exactly what the context menu adds if you enable attribute editing. If you are not happy with the result here, then my above statements are the way to go.
Related
Is there a way to attach a UITextField inside inside the range of an NSAttributedString that is inside a UITextView?
I want to recreate something like this:
Where the user would be able to press the empty lines to type text.
You could calculate a frame for the UITextField like so:
- (CGRect)textFieldFrameForCharacterRange:(NSRange)charRange inTextView:(UITextView *)textView {
NSRange glyphRange = [textView.layoutManager glyphRangeForCharacterRange:charRange actualCharacterRange:NULL];
CGRect boundingRect = [textView.layoutManager boundingRectForGlyphRange:glyphRange inTextContainer:textView.textContainer];
return boundingRect;
}
and then add it as a subview of the UITextView. Determining a character range to pass to the above method can be easy too - just search for a run of underlines, or maybe a custom attribute using - enumerateAttribute:inRange:options:usingBlock:.
The catch is this won't work properly if the underlines are split into more than one line, but UITextField wouldn't fit that case anyway. So you need a way to make sure the underline remains unbroken. The U+2060 unicode character may help, see Prevent line break in a NSAttributedString for more. An NSTextAttachment with the underline represented as an image would also be guaranteed not to get word wrapped.
Alternatively, you could implement a UITextViewDelegate, or possibly even a UITextView subclass, that disallows selection and editing outside of the underline ranges. That way you can avoid the weirdness of UITextFields within UITextViews. But the drawback with this method is even if you deleted an underline character every time the user types a character, the user would still see the overall length of the underline fluctuating slightly.
I'm using this method to change color to few chars of my UITextView
+(void)changeColorToTextObject : (UITextView *)textView ToColor : (UIColor *)color FromLocation : (int)location WithLength : (int)length
{
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithAttributedString: textView.attributedText];
[text addAttribute:NSForegroundColorAttributeName value:color range:NSMakeRange(location, length)];
[textView setAttributedText: text];
}
It works great but after I change the specific range I want to be able to continue with the previous color and not with the new color that I just changed to.
How can I do it?
Actually, when working with attributed text, I found it best practice to set content first and style second (which actually originates from old typesetting rules).
In your case, I would first set the whole text on the UITextView, and then call the method changeColorToTextObject:ToColor:FromLocation:WithLength specifying only the portion of the text you want in a different color.
However, if you are not talking about static content, but rather something like a word processor app, where the user can change text color and continues to write afterwards, you need to think about how you want this app to work. Consider the following method:
- (void)highlightSelectedText {
UIColor *highlightColor = [UIColor redColor];
[self changeColorToTextObject:self.textView ToColor:highlightColor FromLocation:self.textView.selectedRange.location WithLength:self.textView.selectedRange.length];
}
This method allows you to highlight the specific part of the text, the user has currently selected:
If the user then continues typing, the new text will appear in red:
If instead, they put the focus at a place where font color is black, they will continue writing in black:
When you think about a word processor, that seems actually pretty familiar. And if that is good enough for you, you are good to go.
The only border case you need to worry about then is what you do, when there is no text selected.
However, if you need more control over the dynamic behavior of your UITextView (and if you are >iOS 7), you should consider using Text Kit, and in particular subclassing NSTextStorage. There is a introduction video to Text Kit from WWDC 2013, and a great tutorial by Ray Wenderlich.
Save your previous color into a 'UIColor' property before apply the attributedText to the UITextView, and assign it to the UITextView after using the 'changeColorToTextObject' method.
I am using TTTAttributedLabel for URLs and phone number in my app. Every thing is working fine but the problem is that now I need to show icon in the UILabel. Before I am using given below code. But due to use of TTTAttributedLabel now NSTextAttachment is not showing in TTTAttributedLabel. TTTAttributedLabel does not support attachment. So any idea to support URLs, phone numbers and icons in UILabel?
now i decided to show unicode image in TTTAttributedLabel. and it is working fine.
It's better to use UITextView and set the textView's data detector types.
textView.dataDetectorTypes = UIDataDetectorTypeAddress | UIDataDetectorTypeLink | UIDataDetectorTypePhoneNumber;
There is one delegate methods that is called when the link or url in the text view is selected
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange NS_AVAILABLE_IOS(7_0);
This gives you the URL tapped inside your text view and you can perform your desired action.
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
I want to implement custom text fields. Here is a screenshot of what I want to implement:
So I have a UITableView with cells, and in each cell I have several text fields: one for date, one for name, one for theme, and one for text. But the UI requires theme and text to be next to each other (as can you see in the picture). I wanted to implement this as a single UITextField, but as far as I know, UITextField supports only one type of font. So maybe someone will give me a piece of advice how to implement the design shown in the screenshot — do I have to draw custom text fields, or are there simpler solutions? Any code samples or propositions would be helpful.
For iOS 6:
You can set a UITextField's attributed string:
#property(nonatomic,copy) NSAttributedString *attributedText;
I suggest to use a NSMutableAttributedString and to exploit polymorphism.
A mutable attributed string can hold vary attributes for each piece of the string. So you can add an attribute only for a certain range of the string with this method:
- (void)setAttributes:(NSDictionary *)attributes range:(NSRange)aRange;
For iOS 5:
Use directly this UITextField's property:
- (void)setAttributes:(NSDictionary *)attributes range:(NSRange)aRange;