color change in texts of UITextView - iphone

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.

Related

How to estimate the proper height of a UITextField, to hold text of given font size

I want to display a single-line text field using UITextField and I need to know before displaying it, the proper size for its containing UICollectionViewCell. The text can be one of multiple font sizes and I need to get the right height for displaying it comfortably.
Since the text is not known in advance (it can be edited by the user), I can't use NSAttributedString's -size and -boundingRectWithSize:options:context: with anything but dummy text, in which case I can't really trust the resulting size to hold any piece of text, right?
I guess my question is: Is there a rule of thumb about typography in general, or some useful API I'm not aware of, that would allow me to determine that for displaying text at X pt, I need a text field with a height of Y px.
UITextField implements the sizeThatFits: method. So the most reliable way to get the size of your text field is to actually create one, set it up like you would set up your real text fields, and ask it for a suitable size. You don't even have to give it placeholder text, because UITextField will choose the size based on its font, not on its text.
UITextField *dummy = [[UITextField alloc] init];
dummy.font = [UIFont systemFontOfSize:20];
dummy.borderStyle = UITextBorderStyleRoundedRect;
CGFloat requiredHeight = [dummy sizeThatFits:CGSizeMake(HUGE_VALF, HUGE_VALF)].height;
// requiredHeight == 30 in my test
If your deployment target is iOS 6.0 or later, you can instead use the intrinsicContentSize property, like this:
CGFloat requiredHeight = dummy.intrinsicContentSize.height;
// requiredHeight == 30 in my test
Note that sizeThatFits: still works in iOS 6, but intrinsicContentSize is a little easier to understand.
iOS always returns a height of 30 units when the borderStyle is RoundedRect. If you want to compute the height required by a custom font, you have to change the borderStyle to any other value, compute the height, and change the borderStyle back.
textField.borderStyle = UITextBorderStyle.None;
let sizeThatFits = textField.sizeThatFits(CGSize(width:textField.bounds.width, height: CGFloat.max));
textField.bounds.height = sizeThatFits.height;
textField.borderStyle = UITextBorderStyle.RoundedRect;

UITextView - modifying selected text

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

problem in Text Alignment for label in iphone SDK

We have label with text in 2 lines. In second line the text is not aligning exactly to the left as in the first line. we had set property for the label as number of lines = 0.
for Ex:
label.text = #"This is the text for the label."
In Result We are getting this as
This is the text
for the label.
But we want this as
This is the text
for the label.
try setting the word wrap of button:
[label setNumberOfLines:0]
Edit:
just realised there's linebreak property of label, that should help
label.lineBreakMode = UILineBreakModeWordWrap;

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

String length with given font to fit UITextView

I need to move text that the user has entered into a large multi-line UITextView into a smaller (but still multi-line) UITextView*. If the user has entered more text than will display in the smaller view, I want to truncate the text so that it fits with all the (truncated) text visible. (Neither the large UITextView nor the smaller one should scroll.)
What's the best way to do this?
I can use a loop, shortening the string by a character each time, and then use NSString's sizeWithFont: constrainedToSize: lineBreakMode: to find out the height this shorter string would need, and then compare that against the height I have available in my smaller UITextView, ending the loop when the string will fit - but that seems slow and awkward. There must be a better way.
I'd like to just tell the destination UITextView to truncate its displayText member as it displays it on screen, but I've not been able to find a way to do that.
*More context on this, from a comment I made below:
I've got a landscape app. I change the layout of the view depending on the photo the user chooses. If it's a landscape photo, the caption is smaller - just a line at the bottom of the photo. If she chooses a portrait photo, then there's plenty of space I can use for the caption at the side of the photo, so the caption is bigger.
If the user changes her photo orientation from portrait to landscape, then I want to truncate the text and then allow her to edit it so that it makes sense. I could just zap it, but I'd prefer to preserve it to minimize her typing.
I wrote the following recursive method and public API to do this properly. The ugly fudge factor is the subject of this question.
#define kFudgeFactor 15.0
#define kMaxFieldHeight 9999.0
// recursive method called by the main API
-(NSString*) sizeStringToFit:(NSString*)aString min:(int)aMin max:(int)aMax
{
if ((aMax-aMin) <= 1)
{
NSString* subString = [aString substringToIndex:aMin];
return subString;
}
int mean = (aMin + aMax)/2;
NSString* subString = [aString substringToIndex:mean];
CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight);
CGSize stringSize = [subString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
if (stringSize.height <= self.frame.size.height)
return [self sizeStringToFit:aString min:mean max:aMax]; // too small
else
return [self sizeStringToFit:aString min:aMin max:mean];// too big
}
-(NSString*)sizeStringToFit:(NSString*)aString
{
CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight);
CGSize stringSize = [aString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
// if it fits, just return
if (stringSize.height < self.frame.size.height)
return aString;
// too big - call the recursive method to size it
NSString* smallerString = [self sizeStringToFit:aString min:0 max:[aString length]];
return smallerString;
}
This isn't actually a fix but it does provide a good starting poing for the calculation.
If you use NSString's sizeWithFont: constrainedToSize: lineBreakMode: you get a vertical height for your text. If you divide that by your font's leading height, you get the number of lines in the whole string. Dividing [NSString count] by that number gives you an approximation to number of characters per line. This assumes the string is homogeneuous and will be inaccurate if someone types (e.g.) 'iiiiiiiiiii..." as oposed to "MMMMMMMMM...".
You can also divide you bounding box by the relevent font's leading height to get the number of lines that fit within your bounding box.
Multiplying characters per line by number of lines gives you a starting point for finding text that fits.
You could calculate the margin for error in this figure by doing the same calculation for those 'iiiiii...' and "MMMMMM...'" strings.
I would suggest taking a slightly different approach and seeing if you can use a UILabel instead of the smaller UITextView.
UILabels can be setup to be multi-line like a UITextView through their numberOfLines property.
UILabels also have a lineBreakMode property and I believe that the default value of that property will do the exact truncation effect that you are looking for.
I think Jonathan was on to something about the UILabel...
So, the user finishes editing the UITextView, you get the string of text and pass it to the UILabel. You change the alpha of the UITextView to 0 and/or remove it from superview. Possibly store the untruncated full text in an ivar.
UILabels are not "editable", however you can detect a touch with a UILabel (or it's superview).
When you detect the touch on the UILabel, you simply restore the hidden UITextView and restore the string you saved.
Sometimes the SDK is a pain, but it almost always wins the fight. Many times, it is better to adjust your design to UIKit conventions