UITextView - modifying selected text - iphone

I have a UITextView and i want to select a certain part of this text and modify its style. Like changing the color, making it italic or bold, increasing the font size, or changing the font family.
Any Help?

Yes. Wait for iOS 5. I think most of the info about iOS 5 is still under NDA, so we can't discuss it here.
Or develop it all yourself with CoreText.

You can use some alternative things as follows:-
First take a scrollview and add a label or another textview with different style as you want with bold font or chagne color and add as subview in scrollview.
For textviews added in scrollview, you should take a frame of that textview as larger as text or lines in textview for stop scrolling in textview because we already added textview in scrollview for better look.
So,Take as many textviews or labels or images as your need and add then to the scrollview things are very simple you can do this using an Interface builder. Just need to define a perfect content size for scrollview depends on subviews you have.

You should use shouldChangeTextInRange. This is because you need range to locate the position where you want the text changed.
UITextView lets you save your style in textView.attributedString.
The solution is to get textView's Attributed String and replace the desired sub string in it with changed or styled text.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
NSMutableAttributedString *textViewText = [[NSMutableAttributedString alloc]initWithAttributedString:textView.attributedText]; //gets textView style string
NSRange selectedTextRange = [textView selectedRange];
NSString *selectedString = [textView textInRange:textView.selectedTextRange]; //our selected text
//lets say you always want to make selected text bold
UIFont *boldFont = [UIFont boldSystemFontOfSize:self.txtNote.font.pointSize];
NSDictionary *boldAttr = [NSDictionary dictionaryWithObject:boldFont forKey:NSFontAttributeName];
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc]initWithString:selectedString attributes:boldAttr]; //make attributed string of our selectedtext
[textViewText replaceCharactersInRange:range withAttributedString:attributedText]; // replace
textView.attributedText = textViewText;
return false;
}

Related

color change in texts of UITextView

i am novice in iPhone.
I have a textView. I am changing the background Color of selected texts in text View.
But problem is that when I am selecting more than 1 line in textView ,only first line color is being changed , not other lines color.
so can anyone tell me about this how can I change background color of all texts which i m selecting.??
tagValue = textView.tag;
NSRange r = textView.selectedRange;
UITextRange *selectedRange = [textView selectedTextRange];
if (!selectedRange)
return;
CGRect result1 = [textView firstRectForRange:selectedRange];
frame_selectedText = result1;
self.str_selected =[NSString stringWithFormat:#"%#", [textView.text substringWithRange:NSMakeRange(r.location, r.length)]];
UIButton *btnView = [UIButton buttonWithType:UIButtonTypeCustom];
[btnView setFrame:result1];
[btnView addTarget:self action:#selector(buttonColorClicked:) forControlEvents:UIControlEventTouchUpInside];
btnView.backgroundColor = [UIColor colorWithRed:220.0f/255.0f green:248.0f/255.0f blue:188.0f/255.0f alpha:0.5];
[textView addSubview:btnView];
The reason this is happening is that firstRectForRange will give you a rectangle that will not cover more than 1 line. As long as the text/selected text remains in one line, the rect will cover that.
Reason being: Imagine you select text that spans to a line and a half. So when you select the text, the selection color will show you that the selection boundary is not a rectangle. It is more like an inverted L. Hence, a single rect cannot cover it.
If you want to highlight just the selected text, you will have to use multiple rects. See my code here. I have covered multiple lines, and words with different rectangles. You can set a color and transparency (alpha) to give a feeling of highlighting. But the drawback here would be, you will not be able to interact with that text.
If you want to create a single rectangle that covers all of your selected text, then it will cover text succeeding the selected text, but you can work with a single rectangle. For this you will have to use firstRectForRange twice. Once on the first word selected, and second on the first word selected in the last line of selected text. The use MAX and MIN to create a single rect that covers all your text.
Alternate method
UITextViews support AttributedTexts. With this you can set text of UITextView with a string with multiple attributes (bold, italic, colored text, colored background etc). Use NSMutableAttributedStrings to store your text. Add attributes like this:
[myAttriButedText addAttribute:NSBackgroundColorAttributeName value:UIColorFromRGB(0x333333) range:NSMakeRange(0, [myAttriButedText length])];
And set the text of UITextView using setAttributedText, or textView.attributedText =. This way, you easily add a background color on your text, without the hassles of all the above mentioned. But if you want more that just the attributes supported by NSAttributedStrings, you will have to use above mentioned methods.

How to create a UILabel or UITextView with bold and normal text in it?

I am trying to create a UILabel or UITextView with bold and normal text inside.
I have gone through the attributedstring but when I am setting this in label of my custom cell it doesn't display any text.
I have also used the UITextView setContentToHTMLString: method, but it is undocumented and app get rejected.
Can anyone give some sort of solution to this?
Use "NSAttributedString" to set multiple font text in a single label & use CATextLayer to render it:
just #import "NSAttributedString+Attributes.h"
and then implement it like this:
NSString *string1 = #"Hi";
NSString *string2 = #"How are you ?";
NSMutableAttributedString *attr1 = [NSMutableAttributedString attributedStringWithString:string1];
[attr1 setFont:[UIFont systemFontOfSize:20]];
NSMutableAttributedString *attr2 = [NSMutableAttributedString attributedStringWithString:string2]
[attr2 setFont:[UIFont boldSystemFontOfSize:20]];
[attr1 appendAttributedString:attr2]
CATextLayer *textLayer = [CATextLayer layer];
layer.string = attr1;
layer.contentsScale = [[UIScreen mainScreen] scale];
(Your_text_label).layer = textLayer;
OR (if you want to render on a view directly)
[(Your_View_Name).layer addSublayer:textLayer];
Up until iOS 6.0, you couldn't do this with a normal UILabel or UITextView, but you can use NSAttributedString objects with a few possible open source solutions.
Like TTAttributedLabel or OHAttributedLabel.
One solution built into the iOS SDK, you could also use a CATextLayer which has a string property that can be set to a NSAttributedString.
And, like the commenters below say, yes you can do this with the "attributedText" property. Horray! (for Apple listening to developer's very often repeated feature requests)
I know this is an old thread, but this is something I just discovered myself. At least in Xcode version 4.6.3 this is possible by using an attributed textView. What's even better is that it's possible to all be done in Interface Builder!
Here are the steps:
Place your textView at the desired location
Select the textView and open up the Attributes tab under the Utilities panel
Change the textView text to "attributed"
Enter your desired text
Now, highlight whatever text you want bolded, underlined, etc.
Click on the "T" button next to the fontName
In the popup, select your desired typeface (ex: Bold)
You should see the desired typeface displayed in the Utilities panel
Enjoy!
The following code is for iOS 6.0 and above. The result is that the text "This is bold" will be in bold and "This is not bold." will be normal text.
if ([self.registrationLabel respondsToSelector:#selector(setAttributedText:)])
{
// iOS6 and above : Use NSAttributedStrings
const CGFloat fontSize = 17;
UIFont *boldFont = [UIFont boldSystemFontOfSize:fontSize];
UIFont *regularFont = [UIFont systemFontOfSize:fontSize];
//UIColor *foregroundColor = [UIColor clearColor];
// Create the attributes
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
boldFont, NSFontAttributeName, nil];
NSDictionary *subAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
regularFont, NSFontAttributeName, nil];
const NSRange range = NSMakeRange(0,12); // range of " 2012/10/14 ". Ideally this should not be hardcoded
// Create the attributed string (text + attributes)
NSString *text = #"This is bold and this is not bold.;
NSMutableAttributedString *attributedText =
[[NSMutableAttributedString alloc] initWithString:text
attributes:subAttrs];
[attributedText setAttributes:attrs range:range];
// Set it in our UILabel and we are done!
[self.registrationLabel setAttributedText:attributedText];
}
If you have an issue with editing the attributed text in the inspector, copy/paste the text into a rich text editor, adjust it, switch the textView Text options to Attributed and paste. Vwala.

How can I get the UITextView to scroll only when it's full of text

I have this UITextView that works great except, I can't get the text inside the UITextView to start scrolling only after the UITextView's size in nearly full, the UITextView is 4 lines tall, but as soon as I reach the 2nd line the 1st line is pushed up, I don't want the view to begin scrolling until I've reached the 5 line. scrollingEnabled = NO keeps it from scrolling at all, so that didn't work.
UITextView *barf_ = [[UITextView alloc] initWithFrame:CGRectMake(20.0, 310.0, 155, 50)];
barf_.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
//[barf_ scrollRangeToVisible:NSMakeRange([barf_.text length], 0)];
barf_.layer.cornerRadius = 3.0f;
barf_.layer.borderWidth = 0.5f;
barf_.font = [UIFont fontWithName:#"Helvetica" size:13];
I found the answer, as others with similar problems have mention, with a small textView, it automatically adds 32 padding to the bottom.
A simple fix is to add YourTextView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0); inside shouldChangeTextInRange method, that fixed my problem!
Setting the contentInset may help the text to appear more correctly within the UITextView. However, it won't help solve the issue whereby the UITextView has scrolling enabled despite not having more text to view.
Similarly, methods such as sizeWithFont have limitations. As explained in Mike Weller's excellent blog series iOS Development: You're Doing It Wrong, NSString isn't a good object to ask regarding how large a UIView should be. Many UIView subclasses such as UILabel, UIButton, etc. have insets and other considerations that must be accounted for during sizing. UITextLabel is no exception.
Mike Weller's particular entry on this subject is:
You're Doing It Wrong #2: Sizing labels with -[NSString sizeWithFont:...]
iOS 7 promises us more sophisticated text handling in UITextView, with properties such as textContainerInset. But what to do in the meantime?
Well, first we know that UITextView is a subclass of UIScrollView. Therefore, the golden rule that if the contentSize is larger than the view's bounds property, the scroll view will scroll so we can see more content.
Checking out contentSize agains the bounds won't work either because we know that UIScrollView is already calculating whether it should scroll or not based on the text, and it's giving us the wrong answer.
This is where arbitrary adjustment values come to the rescue! For me this value was 17.f. For you - depending on your fonts - it maybe different. We then take control and decide whether we should allow the scroll view to scroll:
static const CGFloat kArbritaryHeight = 17.f;
CGFloat adjustedContentHeight = myTextView.contentSize.height - kArbritaryHeight;
CGFloat boundsHeight = CGRectGetHeight(myTextView.bounds);
BOOL tooMuchContent = adjustedContentHeight > boundsHeight;
if (tooMuchContent)
{
myTextView.scrollEnabled = YES;
}
else
{
myTextView.scrollEnabled = NO;
}
When your UITextView is loaded set scrollEnabled to NO. Then set the text view's delegate to self or some other object and implement the UITextViewDelegate method
- (void)textViewDidChange:(UITextView *)textView
This method will get called anytime the user makes a change to the text inside the view. Inside this method you need to figure out how big your text is and if it goes beyond the bounds of the text view. If so you enable scrolling. Use this method:
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode
This is a UIKit category method on NSString. It returns a CGSize that will tell you the height of whatever text string you call it on. In your case it would be something like
CGSize textSize = [textView.text sizeWithFont:textView.font
constrainedToSize:CGSizeMake(textView.frame.size.width, MAXFLOAT)
lineBreakMode:UILineBreakModeWordWrap];
if (textSize.height > textView.frame.size.height) {
textView.scrollEnabled = YES;
} else {
textView.scrollEnabled = NO;
}
You might use the sizeWithFont:constrainedToSize:lineBreakMode: method to check whether your string will actually render larger than your text view and see if you need to enable scrolling. You will have to call it any time the text in your scrollview is set, however.
ex:
CGSize barfStringSize = [barfString sizeWithFont:[barf_ font]
constrainedToSize:CGSizeMake(barf_.bounds.size.width, MAXFLOAT)
lineBreakMode:UILineBreakModeWordWrap]
[barf_ setScrollEnabled:barfStringSize.height > barf_.bounds.size.height]

UItextView arabic text aligned to right

Using my custom arabic keyboard on UItextView inputView, I m filling my textView with the arabic text but cannot get the written text align to right....Need help to align text to right.
-(BOOL)textViewShouldBeginEditing:(UITextView *)textView{
if(showCustomKeyboard==NO){
[textView resignFirstResponder];
textView.inputView=nil;
[textView becomeFirstResponder];
return YES;
}
else{
[textView resignFirstResponder];
if(customKeyboard==nil){
customKeyboard=[[CustomKeyboard alloc] initWithFrame:CGRectMake(0, 264, 320, 216)];
[customKeyboard setDelegate:self];
}
if([[UIApplication sharedApplication] respondsToSelector:#selector(inputView)]){
if (textView.inputView == nil) {
textView.inputView = customKeyboard;
[textView becomeFirstResponder];
}
}
self.customKeyboard.currentField=textView;
[textView becomeFirstResponder];
}
return YES;
}
You can set the writing direction of a UITextView using the setBaseWritingDirection selector:
UITextView *someTextView = [[UITextView] alloc] init];
[someTextView setBaseWritingDirection:UITextWritingDirectionLeftToRight forRange:[someTextView textRangeFromPosition:[someTextView beginningOfDocument] toPosition:[someTextView endOfDocument]]];
The code is a little tricky because UITextView supports having different parts of the text with different writing directions. In my case, I used [someTextView textRangeFromPosition:[someTextView beginningOfDocument] toPosition:[someTextView endOfDocument]] to select the full text range of the UITextView. You can adjust that part if your needs are different.
You may also want to check whether the text in your UITextView is LTR to RTL. You can do that with this:
if ([someTextView baseWritingDirectionForPosition:[someTextView beginningOfDocument] inDirection:UITextStorageDirectionForward] == UITextWritingDirectionLeftToRight) {
// do something...
}
Note that I specified the start of the text using [someTextView beginningOfDocument] and searched forward using UITextStorageDirectionForward. Your needs might differ.
If you subclass UITextView replace all these code samples with "self" and not "someTextView", of course.
I recommend reading about the UITextInput protocol, to which UITextView conforms, at http://developer.apple.com/library/ios/#documentation/uikit/reference/UITextInput_Protocol/Reference/Reference.html.
Warning about using the textAlignment property in iOS 5.1 or earlier: if you use it with this approach together with setting the base writing direction, you will have issues because RTL text when aligned left in a UITextView actually aligns to the right visually. Setting text with an RTL writing direction to align right will align it to the left of the UITextView.
Try textAlignment property.
textView.textAlignment = UITextAlignmentRight;
Take a look at UITextView Class Reference.
EDIT: Maybe CATextLayer can help you, someone suggests to use this class to customize text, but I've never used it personally...
Otherwise, you can force your textView to reverse your input in UITextFieldDelegate method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
The text field calls this method whenever the user types a new character in the text field or deletes an existing character.
Here you can replace your input with a new NSString where you put the characters from right to left.
Hope this makes sense...
Ah... Do not forget to set
textView.textAlignment = UITextAlignmentRight;
to move your prompt on the right.
Try this code:
yourtextview.textAlignment = UITextAlignmentRight;
Hope this helps you.
Something which no one mentioned here or on any other post is that make sure you have not called sizeToFit for TextView. It simple aligns the textView (not text) to the left which gives the illusion that text is left to right instead of right to left.
If you are creating UI from Storyboard, the set constraint to Lead or Trailing space and value of First Item will be Respect Language Direction
in swift you can use this code
textView.makeTextWritingDirectionRightToLeft(true)

Best way to strike out a text

What is the best solution so far for a strike out text on the iPhone?
I heard of multiple solutions:
Something with three20
Image as a subview
UIWebView
And something with a NSAttributedString, but I don't find a working example for that.
In iOS 6 we can use "NSMutableAttributedString" for use more different styles.
NSString* cutText = #"This Line is strike out.";
NSMutableAttributedString *titleString = [[NSMutableAttributedString alloc] initWithString:cutText];
// making text property to strike text- NSStrikethroughStyleAttributeName
[titleString addAttribute:NSStrikethroughStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:NSMakeRange(0, [titleString length])];
// using text on label
[myTextLabel setAttributedText:titleString];
You can try my solution of UILabel subclass, which supports:
multiline text with various label bounds (text can be in the middle of label frame, or accurate size)
underline
strikeout
underline/strikeout line offset
text alignment
different font sizes
https://github.com/GuntisTreulands/UnderLineLabel