UIScrollView content offset is reset

I struggled with a problem with UIScrollView for a long time.

I have a UIScrollVIew that contains a UITextView as a subview. When I select a text view, a keyboard appears. I want to resize the text view so that it exactly matches the available space, and also scroll to scroll so that the text view is located exactly in the visible space (not hidden by the keyboard).

When the keyboard appears, I call a method that calculates the appropriate size for the text view, and then executes the following code:

 [UIView animateWithDuration:0.3 animations:^ { self.textView.frame = frame; } ]; [self.scrollView setContentOffset:CGPointMake(0,frame.origin.y) animated:YES]; 

(here the frame is the corresponding frame for the text view).

Unfortunately, the scroll view will not always move to the desired position, especially when it is already in a non-zero vertical offset of the content when I select the text view. I know that the content offset that I set is correct.

After much testing, I finally realized that what happened was that after the animation ended, the scroll automatically scrolled.

This code works:

 UIView animateWithDuration:0.3 animations:^ { self.textView.frame = frame; } completion:^(BOOL finished) { [self.scrollView setContentOffset:CGPointMake(0, frame.origin.y) animated:YES]; } ]; 

but it looks weird because the scroll scrolls to the wrong position and then to the right.

Does anyone know how I can prevent a scroll view from changing its content offset when the frame of a text view completes its animation?

I am testing using iOS 5.0.


Here is the solution I found that works. I still do not quite understand what is happening, perhaps this has something to do with how my springs and struts are installed. I basically reduce the size of the contents of the scroll view by the same amount as the text view.

 - (void)keyboardDidShow:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; // Get the height of the keyboard CGRect kbRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue]; kbRect = [self.view convertRect:kbRect fromView:nil]; CGSize kbSize = kbRect.size; // Adjust the height of the text view to fit in the visible view CGRect frame = self.textView.frame; int visibleHeight = self.view.frame.size.height; visibleHeight -= kbSize.height; frame.size.height = visibleHeight; // Get the new scroll view content size CGSize contentSize = self.scrollView.contentSize; contentSize.height = contentSize.height - self.textView.frame.size.height + frame.size.height; [UIView animateWithDuration:0.1 animations:^ { self.textView.frame = frame; // Note that the scroll view content size needs to be reset, or the scroll view // may automatically scroll to a new position after the animation is complete. self.scrollView.contentSize = contentSize; [self.scrollView setContentOffset:CGPointMake(0, frame.origin.y) animated:YES]; } ]; // Turn off scrolling in scroll view self.scrollView.scrollEnabled = NO; } // Called when the UIKeyboardWillHideNotification is sent - (void)keyboardWillBeHidden:(NSNotification*)aNotification { // Update the view layout [UIView animateWithDuration:0.3 animations:^ { self.scrollView.contentOffset = CGPointZero; [self updateViewLayout]; } ]; // Turn on scrolling in the scroll view self.scrollView.scrollEnabled = YES; } 

( [self updateViewLayout] is a method that returns the text view to the correct height and resets the size of the scroll content, and also ensures that all other subviews are correctly positioned).

+4
source share
4 answers

Do not adjust the frame of the text view. All you have to do is scroll the scroll. If you scroll the scrollview animation, then the textView will move up. Just follow these steps:

 [self.scrollView setContentOffset:CGPointMake(0, frame.origin.y) animated:YES]; 

If you need to scroll to scroll at a specific speed, then manually adjust the content offset in the animation block. (I have not tested this, you can configure the animation checkbox or go through shifting the contents of one pixel at a time if this does not work)

 [UIView animateWithDuration:0.3f animations:^{ [self.scrollView setContentOffset:CGPointMake(0, frame.origin.y) animated:YES]; } ]; 
+3
source

I believe that I also had something similar. I wanted my horizontal UIScrollView to go back to its original offset (0,0), and every time I go back to it, it would be just a couple of pixels, but as soon as someone touches the scroll, it will continue and end the animation (almost like a lag in a video game).

In this regard, I tried to put it in the GCD as the main queue, and after that it did an excellent job. Here is the code:

 - (void)setPageZero{ dispatch_async(dispatch_get_main_queue(), ^{ [UIView animateWithDuration:1.0f delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ [self.scrollView setContentOffset:CGPointMake(0, self.scrollView.frame.origin.y) animated:YES]; } completion:^(BOOL finished) {}]; }); } 

What this basically does is that it puts the animation in the main queue (like a superhighway in the CPU / GPU), and it gives priority to other things!

Hope this helps future readers!

+3
source

I have the same problem. Basically I have a scroll with three pages, each of which contains a custom UIView class. A custom UIView class contains an image and several types of overlays containing image information. Overlay views contain several UITextView fields.

I attach custom views to the scroll view, and then load the image and overlay using block operations. I scroll to the right, removing the first view, rearranging the next two views, and adding a new view to the right.

If I create UITextField objects and turn off scrolling as follows:

 UITextView* view = [[UITextView alloc] initWithFrame:CGRectMake(position.x,position.y,width,height)]; view.editable = NO; view.scrollEnabled = NO; 

Then the scroll view moves between pages when I return from the block code. Please note that I do not move the scroll view and when I exit the block, the scroll view is in the correct position.

However, if I comment out the code to disable scrolling

 UITextView* view = [[UITextView alloc] initWithFrame:CGRectMake(position.x,position.y,width,height)]; view.editable = NO; // view.scrollEnabled = NO; 

this move does not occur, and the scrolling works as expected.

+2
source

Full hack: may improve reset problem:

 - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { [self setContentOffset:self.contentOffset animated:NO]; } 
0
source

Source: https://habr.com/ru/post/1396336/


All Articles