UIScrollView scrolling issue - iphone

I have a scrollview which works perfectly until I dismiss the keyboard. After that it scrolls but not all the way down anymore... I am a bit puzzled.
in viewDidLoad I save the frame so I can reset it later
frame = self.scrollView.frame;
NSLog(#"Height beginning: %f",self.scrollView.frame.size.height);
offset = self.scrollView.contentOffset;
For debugging I checked the scrollview's height which is 629
in my keyboardDidHide method I set the old frame back
self.scrollView.frame = frame;
NSLog(#"Height end: %f",self.scrollView.frame.size.height);
// Reset the scrollview to previous location
self.scrollView.contentOffset = offset;
The debugging output is 629 as well which means that the scrollview's height has been set to the old value. It does scroll but when I let go it bounces all the way back to the beginning...
EDIT:
When using 480 as height it is not filling the whole screen because of iphone 4
Some code
-(void) keyboardDidShow: (NSNotification *)notif
{
NSLog(#"Keyboard is visible");
// If keyboard is visible, return
if (keyboardVisible) {
NSLog(#"Keyboard is already visible. Ignore notification.");
return;
}
// Get the size of the keyboard.
CGRect keyboardEndFrame;
[[notif.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
// Resize the scroll view to make room for the keyboard
CGRect viewFrame = frame;
viewFrame.size.height = 200;
//viewFrame.size.height -= keyboardEndFrame.size.height;
self.scrollView.frame = viewFrame;
offset = self.scrollView.contentOffset;
CGRect textFieldRect;
if(!activeField)
textFieldRect = comment.frame;
else
textFieldRect = activeField.frame;
textFieldRect.origin.y += 10;
[self.scrollView scrollRectToVisible:textFieldRect animated:YES];
// Keyboard is now visible
keyboardVisible = YES;
}
-(void) keyboardDidHide: (NSNotification *)notif
{
// Is the keyboard already shown
if (!keyboardVisible) {
NSLog(#"Keyboard is already hidden. Ignore notification.");
return;
}
//viewFrame.size.height -= keyboardEndFrame.size.height;
self.scrollView.frame = frame;
[self.scrollView setContentSize:CGSizeMake(320, 700)];
// Reset the scrollview to previous location
self.scrollView.contentOffset = offset;
// Keyboard is no longer visible
keyboardVisible = NO;
}

Related

Scrollview's position jumps during animation when contentOffset has value

I'm using the TPKeyboardAvoidingScrollView found here: https://github.com/michaeltyson/TPKeyboardAvoiding
Here are the relevant code blocks from that class:
- (void)keyboardWillShow:(NSNotification*)notification {
if ( !CGRectEqualToRect(priorFrame, CGRectZero) ) return;
UIView *firstResponder = [self findFirstResponderBeneathView:self];
if ( !firstResponder ) {
// No child view is the first responder - nothing to do here
return;
}
priorFrame = self.frame;
// Use this view's coordinate system
CGRect keyboardBounds = [self convertRect:[[[notification userInfo] objectForKey:_UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil];
CGRect screenBounds = [self convertRect:[UIScreen mainScreen].bounds fromView:nil];
if ( keyboardBounds.origin.y == 0 ) keyboardBounds.origin = CGPointMake(0, screenBounds.size.height - keyboardBounds.size.height);
CGFloat spaceAboveKeyboard = keyboardBounds.origin.y - self.bounds.origin.y;
CGFloat offset = -1;
CGRect newFrame = self.frame;
newFrame.size.height -= keyboardBounds.size.height -
((keyboardBounds.origin.y+keyboardBounds.size.height)
- (self.bounds.origin.y+self.bounds.size.height));
CGRect firstResponderFrame = [firstResponder convertRect:firstResponder.bounds toView:self];
if ( firstResponderFrame.origin.y + firstResponderFrame.size.height >= screenBounds.origin.y + screenBounds.size.height - keyboardBounds.size.height ) {
// Prepare to scroll to make sure the view is above the keyboard
offset = firstResponderFrame.origin.y + self.contentOffset.y;
if ( self.contentSize.height - offset < newFrame.size.height ) {
// Scroll to the bottom
offset = self.contentSize.height - newFrame.size.height;
} else {
if ( firstResponder.bounds.size.height < spaceAboveKeyboard ) {
// Center vertically if there's room
offset -= floor((spaceAboveKeyboard-firstResponder.bounds.size.height)/2.0);
}
if ( offset + newFrame.size.height > self.contentSize.height ) {
// Clamp to content size
offset = self.contentSize.height - newFrame.size.height;
}
}
}
// Shrink view's height by the keyboard's height, and scroll to show the text field/view being edited
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]];
self.frame = newFrame;
if ( offset != -1 ) {
[self setContentOffset:CGPointMake(self.contentOffset.x, offset) animated:YES];
}
[UIView commitAnimations];
}
- (void)keyboardWillHide:(NSNotification*)notification {
if ( CGRectEqualToRect(priorFrame, CGRectZero) ) return;
// Restore dimensions to prior size
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]];
self.frame = priorFrame;
priorFrame = CGRectZero;
[UIView commitAnimations];
}
I'm having an issue that when the keyboard starts to hide, the scrollView immediately jumps up so it's origin is above the top of the window. It then animates into its proper position.
I've found out that this only happens when the contentOffset is anything > 0 when the animation runs.
While debugging I noticed the content offset was 54 when the keyboard dismiss animation begins.
I found that if I added this code to the beginning of keyboardWillHide:
priorFrame.size.height -= self.contentOffset;
...then no jump would occur and the animation would run properly, but the scrollView would be too short in the end.
Any ideas?
Also note that the normal frame for my scrollView is (0, 44, 320, 416) because it is positioned below a title bar.
It seems like this might be a bug in UIKit, unsure. I found a fix by animating contentInset instead of the frame.size.height. You can see it in my fork of the project http://github.com/wordofchristian/TPKeyboardAvoiding

Why does the keyboard not show in my UITextView?

I have a container class which is a view controller.
It holds the UITextView for notes and has another view controller as a subview, called it PDFViewController. That one has an array of view controllers, called them PageViewController's, in it and a UIScrollView so i can swipe through the different view controllers from the array.
Each of the PageViewController's has also an UIScrollView, so i can zoom the different pages.
But when I show my UITextView i cannot edit or write anything.
It shows a blinking cursor, but no keyboard and can't write text.
When i highlight a word from the default text, it shows me some dictionary options but the words won't be replaced.
I just don't know where the problem might be.
container.m (View Controller)
- (void) initNotes {
notesVisible = FALSE;
notes = [[UITextView alloc]initWithFrame:CGRectMake(10, 10, note_width, note_height)];
notes.backgroundColor = [UIColor yellowColor];
notes.font = [UIFont fontWithName:#"Arial" size:24];
notes.text = #"Hier ist Platz für Ihre Notizen";
container = [[UIView alloc] initWithFrame:CGRectMake(start_x, start_y, container_width, container_height)];
container.backgroundColor = [UIColor yellowColor];
[container.layer setShadowColor:[[UIColor blackColor] CGColor]];
[container.layer setShadowOffset:CGSizeMake(2.0, 3.0)];
[container.layer setShadowOpacity:0.6];
[container.layer setShadowRadius:5];
container.layer.shouldRasterize = YES;
[container addSubview:notes];
[self.view addSubview:container];
}
- (void) showTextView {
[UIView beginAnimations:#"MoveAndStrech" context:nil];
[UIView setAnimationDuration:0.4];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
container.frame = CGRectMake(start_x, self.view.center.y-container_height, container_width, container_height);
[UIView commitAnimations];
notesVisible = !notesVisible;
}
- (void) hideTextView {
[UIView beginAnimations:#"MoveAndStrech" context:nil];
[UIView setAnimationDuration:0.4];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
container.frame = CGRectMake(start_x, start_y, container_width, container_height);
// [notes resignFirstResponder];
[UIView commitAnimations];
notesVisible = !notesVisible;
}
#implementation PDFViewController
- (void)awakeFromNib
{
painting = false;
dataInstance = [PDFDataInstance sharedInstance];
chapter = [dataInstance chapter];
[self getNumberOfPages];
kNumberOfPages = dataInstance.pages;
// Register observer to be called when a cell from BookmarkPDFController is pressed
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didSelectBookmark:)
name:#"bookmarkPressedinPDFView" object:nil];
// Register observer to be called when a cell from BookmarkPDFController is pressed
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(togglePainting:)
name:#"togglePainting" object:nil];
// view controllers are created lazily
// in the meantime, load the array with placeholders which will be replaced on demand
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < kNumberOfPages; i++)
{
[controllers addObject:[NSNull null]];
}
self.viewControllers = controllers;
[controllers release];
// a page is the width of the scroll view
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height);
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.delegate = self;
scrollView.directionalLockEnabled = YES;
currentPage = [[chapter currentPage] integerValue];
// pages are created on demand
// load the visible page
// load the page on either side to avoid flashes when the user starts scrolling
//
// Load pages based on currentPage cause of when coming from bookmarks
[self loadScrollViewWithPage:currentPage];
[self loadScrollViewWithPage:currentPage+1];
// update the scroll view to the appropriate page
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * currentPage;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
}
- (void)loadScrollViewWithPage:(int)page
{
if (page < 0)
return;
if (page >= kNumberOfPages)
return;
// replace the placeholder if necessary
PageViewController *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null])
{
//page+1 cause CGPDF indexing starts with 1
controller = [[PageViewController alloc] initWithPageNumberAndUrl:page+1: [chapter urlOnFilesystem]];
[viewControllers replaceObjectAtIndex:page withObject:controller];
[controller release];
}
// add the controller's view to the scroll view
if (controller.view.superview == nil)
{
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[scrollView addSubview:controller.view];
}
}
TextView delegates
- (void)textViewDidBeginEditing:(UITextView *)textView {
NSLog(#"begin editing");
}
- (BOOL)textView:(UITextView *)aTextView shouldChangeTextInRange:(NSRange)aRange replacementText:(NSString*)aText
{
NSLog(#"something changed");
return YES;
}
Just want to add another possibility here. In the iOS simulator, make sure the "Hardware/Keyboard/Connect Hardware Keyboard" is not checked. It took me a couple of hours to figure out this. I guess I toggled that option by accidently pressing the shortcut. Not good experience :(
As pictured, Connect Hardware Keyboard should be UN-checked.
Is the UITextView receiving touches? Implement the UITextViewDelegate methods and see if they get called (esp textViewDidBeginEditing: and textView: shouldChangeTextInRange: replacementText:). This way you'll know for sure whether the text view is indeed handling the touches or not.
If it does, then I don't see anything wrong with your code (except you might have accidentally added a view overlapping the textview)
No one asked , but have you set :
notes.editable = YES ;
?
Make sure that in the delegate of your textview. Following method is returning YES.
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
return YES;
}
After you have set the notes delegates, do the following.
- (void)textViewDidBeginEditing:(UITextView *)textView {
if ([textView isEqual:notes]) {
NSLog(#"notes begin editing");
}
}
- (BOOL)textView:(UITextView *)aTextView shouldChangeTextInRange:(NSRange)aRange replacementText:(NSString*)aText {
if ([aTextView isEqual:notes]) {
NSLog(#"something changed in notes");
}
return YES;
}
This should confirm delegates of notes are indeed getting called.
you need to implement your container class with UITextViewDelegate
and add notes.delegate=self; just after initialize the notes object in initNotes method.
Check for 2 things:
Is notes.editable = YES; if so please change it to NO.
2.Check whether your UITextView delegates are called are not. If not Please make sure you include in your implementation file and set notes.delegate = self.
Try without container, just use the UITextView (notes) as the container itself.
Every time you used container use notes instead.
And then dont:
[container addSubview:notes];
[self.view addSubview:container];
Just:
[self.view addSubview:notes];
Tell me how it goes
I had similar behavior, the UITextView not responding to touches and the keyboard not showing.
My UITextView was layered on top of a UICollectionView which was receiving all the touches even though the UITextView was visibly on top.
I fixed it by adjusting the frame of the UICollectionView so that the UITextView has nothing behind it. After that, all the delegate methods were called like a charm.
Hope this helps.
please Refer this one. where ContantView is your view/textfield and _bubbletable is your table.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
[UIView animateWithDuration:0.2f animations:^{
CGRect frame = _ContantView.frame;
frame.origin.y -= kbSize.height;
_ContantView.frame = frame;
frame = _bubbleTable.frame;
frame.size.height -= kbSize.height;
_bubbleTable.frame = frame;
}];
}

(iphone) uiScrollView sensitivity?

I have 2 questions on uiscrollview.
First question:
I have imageviews on uiscrollview(at bottom of screen) and let users to drag the image view out of uiscroll view.
I place fingers on top of the imageView to drag it out but uiscrollview takes the touch and scrolls.
I guess I need to let the imageView gets the touch event first (if the touch event occurred on imageView)
If finger direction is almost horizontal, give the touch event to scrollview so that it can scroll, otherwise(finger direction is not horizontal) let the user drag the imageView.
(I have scrollView.directionalLockEnabled = YES)
I wonder how this can be done?
Second Question:
User can send the imageView back to uiScrollView by double tapping the imageView.
When I do that, the scrollview is not scrollable until I drag out any imageViews in the scrollView.
Don't know what's causing this problem..
Below is my code to send the imageView back to uiscrollview.
aDragView.userInteractionEnabled = NO;
CGPoint contentOffset = self.puzzlePieceScrollView.contentOffset;
float x = contentOffset.x;
int addIndex = x / widthWithPadding;
aDragView.scrollContainerIndex = addIndex;
CGRect newFrame;
int puzzlePieceCount = 0;
[UIView beginAnimations:#"addDragView" context: [aDragView retain]];
for(UIView* subview in [self.puzzlePieceScrollView subviews])
{
if([subview isKindOfClass: [DragView class]])
{
DragView* dragView = (DragView*)subview;
if(dragView.scrollContainerIndex >= addIndex)
{
dragView.scrollContainerIndex += 1;
newFrame = dragView.frame;
newFrame.origin.x += widthWithPadding;
dragView.frame = newFrame;
}
++puzzlePieceCount;
}
}
newFrame = aDragView.frame;
newFrame.origin.x = [self getOriginXForScrollIndex: addIndex];
newFrame.origin.y = self.frame.origin.y + upperPadding;
aDragView.frame = newFrame;
[UIView setAnimationDuration:0.3];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationFinished:finished:context:)];
[UIView commitAnimations];
float newWidth = std::max((puzzlePieceCount+1) * widthWithPadding, [[UIScreen mainScreen] bounds].size.width );
CGSize newContentSize = self.puzzlePieceScrollView.contentSize;
newContentSize.width = newWidth;
self.puzzlePieceScrollView.contentSize = newContentSize;
- (void) animationFinished:(NSString*)animationId finished:(BOOL)finished context:(void*)context
{
if ([animationId isEqualToString:#"addDragView"])
{
DragView* aDragView = (DragView*)context;
// add to puzzlePieceScrollView
CGPoint p;
p = CGPointMake(aDragView.bounds.size.width * 0.5, aDragView.bounds.size.height * 0.5);
CGPoint newCenter = [aDragView convertPoint: p toView: self.puzzlePieceScrollView];
aDragView.center = newCenter;
[self.puzzlePieceScrollView addSubview: aDragView];
aDragView.userInteractionEnabled = YES;
[aDragView release];
}
self.puzzlePieceScrollView.userInteractionEnabled = YES;
}

scroll to a specific textfield in a scrollview/scrollview stop scrolling when keyboard is on screen

I got stuck in here,
I have a custom scrollview in a view this scroll view has an add field button which lets user to add new text field to the scrollview. When user taps on a particular textfield keyboard appears and hide the textfield, to overcome this I followed UICatalog example, but it moves the whole scrollview up
to prevent this I followed UICatalog example and did this
-(void)textFieldDidBeginEditing:(UITextField *)sender
{
if (sender.frame.origin.y>109) {
moveScrollViewUpBy=(sender.frame.origin.y-109+10);
[self viewMovedUp:YES];
}
}
-(void)viewMovedUp:(BOOL)movedUp
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
CGRect rect = formScrollView.frame;
if (movedUp)
{
if(rect.origin.y == 0.0f){
rect.origin.y -= kOFFSET_FOR_KEYBOARD;
rect.size.height += kOFFSET_FOR_KEYBOARD;
}
}
else
{
if(rect.origin.y != 0.0f){
rect.origin.y += kOFFSET_FOR_KEYBOARD;
rect.size.height -= kOFFSET_FOR_KEYBOARD;
}
}
self.formScrollView = rect;
[UIView commitAnimations];
}
here
#define kOFFSET_FOR_KEYBOARD 160.0
but this shifts the scroll view up,
I want that when i tap on a textfield down below in scroll view... scroll view scrolls and that textfield appears....
is it possible to do so....otherwise suggest me some other solution
I have one more query srollview just stop scrolling while the keyboard stays on screen. Is there any way to overcome this
You probably just want to set the scrollView's contentOffset property, rather than adjust its bounds.
Implement the UITextViewDelegate and do the following:
- (void)textViewDidBeginEditing:(UITextView *)textView {
keyboardShowing = YES; //helper ivar
[self sizeToOrientation];
[self.scrollView scrollRectToVisible:textView.frame animated:YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
keyboardShowing = NO;
[self sizeToOrientation];
}
Helper method:
//fit to the appropriate view sizes
- (void)sizeToOrientation {
CGSize size;
if( keyboardShowing )
size = CGSizeMake(320, 190); //make room for keyboard
else
size = CGSizeMake(320, 420); //full height with tabbar on bottom
self.scrollView.frame = CGRectMake(0, 0, size.width, size.height);
}
This works well for me.

UITableView won't scroll after editing view frame and origin

I'm trying to implement a UITextView in a table cell at the bottom of a table view.
I've tried the suggestions here Making a UITableView scroll when text field is selected, and other solutions as well, but they're a bit different because I have to artificially add extra height to the current view in order to create space for the keyboard.
Here's what I added to the previous solution in order to port it to my app.
-(void) keyboardWillShow:(NSNotification *)note {
CGRect frame = self.view.frame;
frame.size.height += keyboardHeight;
frame.origin.y -= keyboardHeight;
self.view.frame = frame;
}
-(void) keyboardWillHide:(NSNotification *)note
{
CGRect frame = self.view.frame;
frame.size.height -= keyboardHeight;
frame.origin.y += keyboardHeight;
}
Doing this will correctly add the height to the view and scroll to the cell, but after restoring the original view's height, scrolling beyond the current visible view becomes impossible, even though there is valid content outside of the boundaries (I see the text view before the scroll bar bounces back).
If I try to save the tableview's frame or bounds (not the view) in keyboardWillShow and restore them in keyboardWillHide, the scrolling will be restored, but the view will be cut in half.
Are there any remedies to this besides hard-coding the additional height to the bottom of the view?
I was able to solve my problem of the locked scrolling by removing the code that edits the view's origin. In addition, I implemented scrolling to the bottom cell by using the tableview's contentSize property in my calculations.
-(void) keyboardWillShow:(NSNotification *)note
{
if(!isKeyboardShowing)
{
isKeyboardShowing = YES;
CGRect keyboardBounds;
[[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &keyboardBounds];
CGFloat keyboardHeight = keyboardBounds.size.height;
CGRect frame = self.view.frame;
frame.size.height += keyboardHeight;
self.view.frame = frame;
CGPoint scrollPoint = frame.origin;
scrollPoint.y += _tableView.contentSize.height - keyboardHeight;
[_tableView setContentOffset:scrollPoint animated:YES];
}
}