Keeping User-Input UITextVIew Content Constrained to Its Own Frame - iphone

Trying to create a large textbox of fixed size.
This problem is very similar to the 140 character constraint problem, but instead of stopping typing at 140 characters, I want to stop typing when the edge of the textView's frame is reached, instead of extending below into the abyss. Here is what I've got for the delegate method. Seems to always be off by a little bit. Any thoughts?
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
BOOL edgeBump = NO;
CGSize constraint = textView.frame.size;
CGSize size = [[textView.text stringByAppendingString:text] sizeWithFont:textView.font
constrainedToSize:constraint
lineBreakMode:UILineBreakModeWordWrap];
CGFloat height = size.height;
if (height > textView.frame.size.height) {
edgeBump = YES;
}
if([text isEqualToString:#"\b"]){
return YES;
} else if(edgeBump){
NSLog(#"EDGEBUMP!");
return NO;
}
return YES;
}
EDIT: As per Max's suggestion below, here is the code that works (note, however, that autocorrect and cut do not work here):
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
CGSize constraint = textView.frame.size;
NSString *whatWasThereBefore = textView.text;
textView.text = [textView.text stringByReplacingCharactersInRange:range withString:text];
if (textView.contentSize.height >= constraint.height) {
textView.text = whatWasThereBefore;
}
return NO;
}

I had similar problem and noticed that sizeWithFont returns the wrong size. I used yourTextView.contentSize instead. So you can add characters, obtain the content size and then delete newly added characters if content size is bigger then the maximum one.
Edit2: fixed
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
UITextView* clone_tv = [[[UITextView alloc] initWithFrame: textView.frame] autorelease];
clone_tv.text = [textView.text stringByReplacingCharactersInRange:range withString:text];
return (clone_tv.contentSize.height <= textView.frame.size.height*2);
}
Notice the clone_tv. We are actually changing the text in clone text view, and not in the real one. In this case autocorrect and cut works. However I recommend you to create some ivar named cloneTextView in your view controller and use it every time. Doing like this you will avoid unnecessary allocations.

Related

Text view scrolling with in a limited frame in iphone?

I had a text view above the keyboard like hangout application in iphone. i need to type the character in that as go on it will increses the content scroll with in that frame only.and also the texts needs to be in the correct allignment,I did that in this manner `
-(void)textViewDidChange:(UITextView *)textView
{
NSString *text1 = [textView text];
CGFloat width = [textView frame].size.width;
CGSize size = [text1 sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(width, 9999) lineBreakMode:UILineBreakModeWordWrap];
textView.contentSize=CGSizeMake([textView frame].size.width, size.height) ;
}
- (BOOL)textViewShouldReturn:(UITextView *)textview
{
[textView1 resignFirstResponder];
return YES;
}
- (BOOL)textViewShouldBeginEditing:(UITextView *)textField
{
//delegate=self;
return YES;
}
`But here the problem is it is dancing .not sticking.when ever i am typing the whole area is moving up and down,i need it to be fixed.and when ever i typed and reached the end point it needs to scroll up.Can any body help me in where i am going wrong?
For set contentSize of UITextView no need any code , by default it provides this so remove your whole code from textViewDidChange: method.
txtView.contentSize = CGSizeMake(320, 800);
Try this and put dis textview on scrollview.

How to scroll `UITextView` programmatically when user enters each line?

How can I scroll my UITextView programmatically when user enters each line.
It is necessary for my textView since keypad hides it at some point as shown below.
I searched lot, but didn't found any appropriate solution, as I am a newbie to iPhone development. I need your valuable help.
when you are opening the keyboard, you should adjust the frame of your textview. In this case reduce the height of your frame by the height of keyboard.
Implement proper code for these two delegate methods.
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
CGRect frm = textView.frame;
frm.height -= KEY_BOARD_HEIGHT;
textView.frame = frm;
}
- (BOOL)textViewShouldEndEditing:(UITextView *)textView;
{
CGRect frm = textView.frame;
frm.height += KEY_BOARD_HEIGHT;
textView.frame = frm;
}
Take a variable for Scrolling position :: int scrollY;
Code for TextView ::
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if ([text isEqualToString:#"\n"])
{
scrollY += 10;
scrMain.contentOffset = CGPointMake(0, scrollY);
}
return YES;
}
Then, when user resign from keyboard, set it to again 0 and scroll to its origin position.
scrollY = 0;
scrMain.contentOffset = CGPointMake(0, 0);
Hope, it may help you.
Thanks.
UITextView scroll text automatically when enter text, you only change UITextView frame to above keyboard and when you dismiss key board reset UITextView frame
- (void)textViewDidBeginEditing:(UITextView *)textView
{
//set frame for text view here
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
//set frame for text view here
}

changing the frame of UITextView as I am typing

I can use the code below to set the size of the textView frame, to approximately match the textView's content (the typed text) when I press a button or whatnot. How would I call this whenever a new character is typed, so that the frame would grow or shrink interactively?
- (IBAction)doneEditingText:(id)sender {
[myTextView resignFirstResponder];
[myTextView setFrame:CGRectMake(myTextView.frame.origin.x, myTextView.frame.origin.y, myTextView.contentSize.width, myTextView.contentSize.height)];
}
Thanks for reading
EDIT :
Implement UITextView delegate in .h file this:
#interface ViewController : UIViewController<UITextViewDelegate>
If yourTextView added from xib then bind delegate with fileowner otherwise in ViewDidLoad add this line:
yourTextView.delegate = self;
Use textView's delegate for your requirement:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
CGSize maximumSize = CGSizeMake(280,999); //specify width of textView and maximum height for text to fit in width of textView
CGSize txtSize = [textView.text sizeWithFont:[UIFont fontWithName:#"Arial" size:16] constrainedToSize:maximumSize lineBreakMode:UILineBreakModeCharacterWrap]; //calulate size of text by specifying font here
//Add UIViewAnimation here if needed
[textView setFrame:CGRectMake(textView.frame.origin.x,textView.frame.origin.y,txtSize.width+10,txtSize.height+10)]; // change accordingly
return YES;
}
You can use something like this repo on GIT which has the almost same functionality that you want-
https://github.com/HansPinckaers/GrowingTextView
it's similar like message app in iPhone.
I just got done implementing this. The problem with the current (as of posting this answer) accepted answer is that the delegate method:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
exposes the textView before the change the user has typed/inserted/deleted is commited. therefore, the resizing you would be achieving would be one character late. UITextView does inherit from a UIScrollView so the text wouldn't clip off of screen but it could lead to some awkward behavior.
My Solution is to use two delegate methods to achieve the resizing effect correctly.
Expanding the UITextView before the character the user typed hits the screen:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSMutableString *tempString = [NSMutableString stringWithString:textView.text];
[tempString replaceCharactersInRange:range withString:text];
//If we are adding to the length of the string (We might need to expand)
if([tempString length]>textView.text.length)
{
//Create a temporaryTextView which has all of the characteristics of your original textView
UITextView *tempTextView = [[UITextView alloc] initWithFrame:CGRectZero];
tempTextView.font = _inputFont;
tempTextView.contentInset = textView.contentInset;
[tempTextView setText:tempString];
//Change this to respect whatever width constraint you are trying to achieve.
CGSize theSize = [tempTextView sizeThatFits:CGSizeMake(192, CGFLOAT_MAX)];
if(theSize.height!=textView.frame.size.height)
{
textView.frame = CGRectMake(115, 310, 192,theSize.height);
return YES;
}
else
{
return YES;
}
}
else
{
return YES;
}
}
And Shrinking after the user has deleted/shrunk the amount of text in the UITextView the character
-(void)textViewDidChange:(UITextView *)textView
{
//We enter this method AFTER the edit has been drawn to the screen, therefore check to see if we should shrink.
if([textView sizeThatFits:CGSizeMake(192, CGFLOAT_MAX)].height!=textView.frame.size.height)
{
//change this to reflect the constraints of your UITextView
textView.frame = CGRectMake(115, 310, 192,[textView sizeThatFits:CGSizeMake(192, CGFLOAT_MAX)].height);
}
}

make a textView scale horizontally as text accumulates

I am trying to make a textView frame scale horizontally as text accumulates. I am using the code blow to try to make this happen. The frame scales vertically as expected, but the size seems to be locked horizontally.
[myTextView setFrame:CGRectMake(myTextView.frame.origin.x, myTextView.frame.origin.y, myTextView.contentSize.width, myTextView.contentSize.height)];
Here is the project (27K) if anyone wants to take a look.
Thanks for reading.
Implement UITextView delegate in .h file this:
#interface ViewController : UIViewController<UITextViewDelegate>
If yourTextView added from xib then bind delegate with fileowner otherwise in ViewDidLoad add this line:
yourTextView.delegate = self;
Use textView's delegate for your requirement:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
CGSize maximumSize = CGSizeMake(2000,40); //specify height of textView and maximum width for text to fit in height of textView as u want text horizontally
CGSize *txtSize = [textView.text sizeWithFont:[UIFont fontWithName:#"Arial" size:16] constrainedToSize:maximumSize lineBreakMode:UILineBreakModeCharacterWrap]; //calulate size of text by specifying font here
//Add UIViewAnimation here if needed
[textView setFrame:CGRectMake(textView.frame.origin.x,textView.frame.origin.y,txtSize.width+10,txtSize.height+10)]; // change accordingly
return YES;
}
Your answer is here at notes-app.

UITableViewCell custom subclass view not updated

In my custom table view cell subclass, the location of one of the textlabel depends on the content of an ivar (NSString). (i.e: if the NSString is the empty string, the location of the textlabel's frame is different).
The position if updated as follow:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
customOverlayCell *myCell = [self.tableView dequeueReusableCellWithIdentifier:#"CustomOverlayCell"];
if ([buildingFName isEqual:#""])
{
CGRect titleLabelFrame = myCell.titleLabel.frame;
titleLabelFrame.origin.y = 45;
[myCell.titleLabel setFrame:titleLabelFrame];
}
return myCell;
}
I have removed parts of code that weren't relevant.
The result is that the layout of the first cells that appear on the screen are properly updated, but the layout of the views that appear after scrolling down aren't updated.
Am I not using dequeueReusableCellWithIdentifier properly? Or is anything else wrong?
Edit:
Solution from EJV:
CGRect titleLabelFrame = myCell.titleLabel.frame;
if ([buildingFName isEqual:#""])
{
titleLabelFrame.origin.y = 45;
} else {
titleLabelFrame.origin.y = 37;
}
[myCell.titleLabel setFrame:titleLabelFrame];
If the frame of the title label is dynamic, then when you dequeue a cell from the table view, the frame could be in either of the two states (when buildingFName is empty and when it has characters). You need to make sure that you set the frame for when buildingFName is not empty. That way, the title label's frame will always be set correctly. So, you need code like this:
CGRect titleLabelFrame = myCell.titleLabel.frame;
if ([buildingFName isEqual:#""])
{
titleLabelFrame.origin.y = 45;
} else {
// Change titleLabelFrame
}
[myCell.titleLabel setFrame:titleLabelFrame];
I'm afraid, it would require subclassing the cell and implementing [UITableViewCell layoutSubviews] to properly lay out your subviews of the cell. This is how I did something similar for a switch table view cell:
- (void)layoutSubviews
{
CGFloat const ESCFieldPadding = 10.0f;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
// call super layout
[super layoutSubviews];
// obtain widths of elements
CGFloat contentWidth = self.contentView.frame.size.width;
CGFloat contentHeight = self.contentView.frame.size.height;
CGFloat switchWidth = self.switchView.frame.size.width;
CGFloat switchHeight = self.switchView.frame.size.height;
CGFloat labelWidth = contentWidth - (4 * ESCFieldPadding) - switchWidth;
// correctly position both views
self.textLabel.frame = CGRectMake(ESCFieldPadding, 0.0f,
labelWidth, contentHeight);
// it is needed to explicitly resize font as for some strange reason,
// uikit will upsize the font after relayout
self.textLabel.font = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]];
CGRect switchFrame = self.switchView.frame;
switchFrame.origin = CGPointMake(contentWidth - ESCFieldPadding - switchWidth,
(contentHeight / 2) - (switchHeight / 2));
self.switchView.frame = CGRectIntegral(switchFrame);
[UIView commitAnimations];
}
try to disable autolayout from your cell