Text view scrolling with in a limited frame in iphone? - 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.

Related

Scrolling when the keyboard activated

I have an app where you have textfields and one textview but when I get the keyboard it hides the lower textfields. How would I do it.
I have tried:
.m:
- (void)textFieldDidBeginEditing:(UITextField *)sender {
CGSize content = _scrollView.contentSize;
_scrollView.contentSize = CGSizeMake(content.width, content.height + 200);
svos = _scrollView.contentOffset;
CGPoint pt;
CGRect rc = [sender bounds];
rc = [sender convertRect:rc toView:_scrollView];
pt = rc.origin;
pt.x = 0;
pt.y -= 200;
[_scrollView setContentOffset:pt animated:YES];
}
- (IBAction)textFieldShouldReturn:(UITextField *)textField {
CGSize content = _scrollView.contentSize;
_scrollView.contentSize = CGSizeMake(content.width, content.height - 200);
[_scrollView setContentOffset:svos animated:YES];
[textField resignFirstResponder];
}
.h:
CGPoint svos;
Although the bottom text fields are still hidden it does scroll to the visible ones
You have obtained the origin of the sender textfield but only move up by 60, thus, the lower textfields are covered by the keyboard. You will need to know the height of the keyboard and calculate the distance to move up. Check this out. It has much of the answer so I will not explain again.
To scroll to the bottom textfield inside a scrollview, add these lines in textFieldDidBeginEditing:
CGSize content = _scrollview.contentSize;
_scrollview.contentSize = CGSizeMake(content.width, content.height + 200);
This will extend your contentSize programmatically so you can scroll to the last textfield and allow the keyboard to cover the empty space.
In textFieldDidEndEditing or textFieldShouldReturn, in your case, add these:
CGSize content = _scrollview.contentSize;
_scrollview.contentSize = CGSizeMake(content.width, content.height - 200);
I used an arbitrary 200 as example. You will need to figure out how much you want.
A drop-in universal solution for moving text fields out of the way of the keyboard in iOS
https://github.com/michaeltyson/TPKeyboardAvoiding
It works perfect for me.
Simply you need to copy the required classes(TPKeyboardAvoidingScrollView or TPKeyboardAvoidingTableView) in your project and in your interface builder file you have to change the UIScrollView class to TPKeyboardAvoidingScrollView or UITableView to TPKeyboardAvoidingTableView, the remaining things will be handled by these classes.
Have you seen the documentation about managing the keyboard? (apple documentation) There is an example of what i think you are working on. Hope it helps.

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.

How can I make a UIScrollView scroll to a UITextView's cursor position?

I have a view which is similar to the notes app - i.e. typing on a lined piece of paper. To make the text and the paper scroll simultaneously, I have disabled the UITextView's scrolling, and instead placed both my UITextView and my UIImageView inside a UIScrollView.
The only problem with this is that, when the user types, the text disappears below the keyboard, because obviously the UIScrollView does not know to scroll to the cursor position.
Is there any simple way I can retrieve the cursor position and tell the UIScrollView to scroll there?
---EDIT---
Starting from something similar here (where someone was trying to do something similar with a UITableView), I have managed to make a growing, editable UITextView with a fixed background that almost scrolls perfectly. The only issues now are:
There is a slight judder as the text moves up if the user types particularly fast.
If the user hides the keyboard, selects text at the bottom of the screen, and then shows the keyboard again, they have to type a couple of letters before the text becomes visible again - it doesn't scroll up immediately.
When the user hides the keyboard, the animation as the scroll view's frame fills the screen doesn't feel quite right somehow.
Here is the code - I'd be really grateful if anyone can refine it further...
#import "NoteEditViewController.h"
#import "RLWideLabelTableCell.h"
#implementation NoteEditViewController
#synthesize keyboardSize;
#synthesize keyboardHideDuration;
#synthesize scrollView;
#synthesize noteTextView;
//
// Dealloc and all that stuff
//
- (void)loadView
{
[super loadView];
UIScrollView *aScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.scrollView = aScrollView; [aScrollView release];
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, noteTextView.frame.size.height);
[self.view addSubview:scrollView];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Get notified when keyboard is shown. Don't need notification when hidden because we are
// using textViewDidEndEditing so we can start animating before the keyboard disappears.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
// Add the Done button so we can test dismissal of the keyboard
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:#selector(doneButton:)];
self.navigationItem.rightBarButtonItem = doneButton; [doneButton release];
// Add the background image that will scroll with the text
CGRect noteImageFrame = CGRectMake(self.view.bounds.origin.x,
noteTitleImageFrame.size.height,
self.view.bounds.size.width, 500);
UIView *backgroundPattern = [[UIView alloc] initWithFrame:noteImageFrame];
backgroundPattern.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"Notepaper-iPhone-Line"]];
[self.scrollView addSubview:backgroundPattern];
[self.view sendSubviewToBack:backgroundPattern];
[backgroundPattern release];
// Add the textView
CGRect textViewFrame = CGRectMake(noteImageFrame.origin.x+27,
noteImageFrame.origin.y-3,
noteImageFrame.size.width-35,
noteImageFrame.size.height);
RLTextView *textView = [[RLTextView alloc] initWithFrame:textViewFrame];
self.noteTextView = textView; [textView release];
self.noteTextView.font = [UIFont fontWithName:#"Cochin" size:21];
self.noteTextView.backgroundColor = [UIColor clearColor];
self.noteTextView.delegate = self;
self.noteTextView.scrollEnabled = NO;
[self.scrollView addSubview:self.noteTextView];
}
- (void)doneButton:(id)sender
{
[self.view endEditing:TRUE];
}
// When the keyboard is shown, the UIScrollView's frame shrinks so that it fits in the
// remaining space
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
float kbHideDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
self.keyboardHideDuration = kbHideDuration;
self.keyboardSize = kbSize;
self.scrollView.frame = CGRectMake(self.view.bounds.origin.x,
self.view.bounds.origin.y,
self.view.bounds.size.width,
self.view.bounds.size.height - kbSize.height);
}
// When the user presses 'done' the UIScrollView expands to the size of its superview
// again, as the keyboard disappears.
- (void)textViewDidEndEditing:(UITextView *)textView
{
[UIScrollView animateWithDuration:keyboardHideDuration animations:^{self.scrollView.frame = self.view.bounds;}];
}
// This method needs to get called whenever there is a change of cursor position in the text box
// That means both textViewDidChange: and textViewDidChangeSelection:
- (void)scrollToCursor
{
// if there is a selection cursor…
if(noteTextView.selectedRange.location != NSNotFound) {
NSLog(#"selectedRange: %d %d", noteTextView.selectedRange.location, noteTextView.selectedRange.length);
// work out how big the text view would be if the text only went up to the cursor
NSRange range;
range.location = noteTextView.selectedRange.location;
range.length = noteTextView.text.length - range.location;
NSString *string = [noteTextView.text stringByReplacingCharactersInRange:range withString:#""];
CGSize size = [string sizeWithFont:noteTextView.font constrainedToSize:noteTextView.bounds.size lineBreakMode:UILineBreakModeWordWrap];
// work out where that position would be relative to the textView's frame
CGRect viewRect = noteTextView.frame;
int scrollHeight = viewRect.origin.y + size.height;
CGRect finalRect = CGRectMake(1, scrollHeight, 1, 1);
// scroll to it
[self.scrollView scrollRectToVisible:finalRect animated:YES];
}
}
// Whenever the text changes, the textView's size is updated (so it grows as more text
// is added), and it also scrolls to the cursor.
- (void)textViewDidChange:(UITextView *)textView
{
noteTextView.frame = CGRectMake(noteTextView.frame.origin.x,
noteTextView.frame.origin.y,
noteTextView.frame.size.width,
noteTextView.contentSize.height);
self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width,
noteTextView.frame.size.height+200);
[self scrollToCursor];
}
// The textView scrolls to the cursor whenever the user changes the selection point.
- (void)textViewDidChangeSelection:(UITextView *)aTextView
{
[self scrollToCursor];
}
// PROBLEM - the textView does not scroll until the user starts typing - just selecting
// it is not enough.
- (void)textViewDidBeginEditing:(UITextView *)textView
{
[self scrollToCursor];
}
Cool that you found my post about it, glad it was helpful!
I believe you may not be seeing the bottom line because of this line:
CGRect finalRect = CGRectMake(1, scrollHeight, 1, 1);
You're creating a 1x1 point box. A single line of text might be something like 20 or 30 points tall (depending on font size). So if you're scrolling this point to visible, it may only be showing the very top pixel of the bottom line - making the bottom line effectively invisible! If you make finalRect a little taller so it covers the whole line, it might work better:
CGRect finalRect = CGRectMake(1, scrollHeight, 1, 30);
Also, you may be calling your scrollRectToVisible code multiple times at once, which can cause "judders". In my code, I only run scrollRectToVisible from textViewDidChangeSelection, and resize the UITextView (if needed) in textViewDidChange. UIScrollView (and by inheritance UITableView) has built-in support to scroll the actively selected element to be visible, which in my testing worked well when simply resizing the UITextView while typing (but not when selecting a specific point inside with a touch).
There is no easy way to find the screen coordinates for any text or cursor in a UITextView.
What you should do is registering for UIKeyboardWillShowNotification and UIKeyboardWillShowNotification. And in the callbacks you adjust the size or contentInsets of the UIScrollView to adjust for the size of the keyboard.
The size of the keyboard, and even the animation duration is provided in the notifications userInfo, so you can do it in a nice animated fashion.
You find more information and sample code here: http://developer.apple.com/library/ios/#documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html
Not strictly an answer to your question, but here's a different approach to the notes lined background trick: http://www.cocoanetics.com/2010/03/stuff-you-learn-from-reverse-engineering-notes-app/
I've used it and it works well.