UITextView does not scroll on top when loading

When I have text that does not populate the UITextView, it scrolls up as needed. When there is more text on the screen than on the screen, the UITextView scrolls to the middle of the text, not the top.

Here are some potentially important details:

In viewDidLoad, to get some padding on top and bottom of a UITextView:

self.mainTextView.textContainerInset = UIEdgeInsetsMake(90, 0, 70, 0); 

UITextView uses auto-layout to snap 20px to the top, bottom, and each side of the screen (done in IB) to provide different screen sizes and orientations.

I can still scroll it with my finger after loading it.

EDIT I ​​found that removing the auto-layout constraints and then fixing the width seems to fix the problem, but only for that screen width.

+47
ios autolayout uitextview
Jan 20 '15 at 18:59
source share
11 answers

UITextView is a subclass of UIScrollView, so you can use its methods. If all you want to do is make sure it scrolls up, and then where the text is added, try:

 [self.mainTextView setContentOffset:CGPointZero animated:NO]; 

EDIT: AutoLayout with any kind of scrolling quickly becomes fast. The fact that setting a fixed width decides is not surprising. If it does not work in -viewDidLayoutSubviews , this is odd. Setting the layout constraint manually may work. First create restrictions in IB:

 @property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewWidthConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewHeightConstraint; 

and then in the ViewController

  -(void)updateViewConstraints { self.textViewWidthConstraint.constant = self.view.frame.size.width - 40.0f; self.textViewHeightConstraint.constant = self.view.frame.size.height - 40.0f; [super updateViewConstraints]; } 

You may still need setContentOffset in -viewDidLayoutSubviews .

(Another method would be to create a layout constraint for “equal” and “equal” heights between the text element and its supervision with a constant of “-40.” It only “equals” if the constant is zero, otherwise it is set by a constant, but since you can only add this restriction to a view that restricts both views, you cannot do this in IB.)

You may ask yourself if I should do this, what is AutoLayout? I studied AutoLayout in depth and this is a great question.

+18
Jan 20 '15 at 19:11
source share

add the following function to the controller class of the view ...

Swift 3

 override func viewDidLayoutSubviews() { self.mainTextView.setContentOffset(.zero, animated: false) } 

Swift 2.1

 override func viewDidLayoutSubviews() { self.mainTextView.setContentOffset(CGPointZero, animated: false) } 

Goal c

 - (void)viewDidLayoutSubviews { [self.mainTextView setContentOffset:CGPointZero animated:NO]; } 
+116
Dec 13 '15 at 6:50
source share

Swift

 self.textView.scrollRangeToVisible(NSMakeRange(0, 0)) 

Objective-c

 [self.textView scrollRangeToVisible:(NSMakeRange(0, 0))]; 
+11
May 31 '16 at 16:04
source share

I had the same problem! Reset to suggested limitations and just put (y offset)

 @IBOutlet weak var textContent: UITextView! override func viewDidLoad() { textContent.scrollsToTop = true var contentHeight = textContent.contentSize.height var offSet = textContent.contentOffset.x var contentOffset = contentHeight - offSet textContent.contentOffset = CGPointMake(0, -contentOffset) } 
+9
07 Feb '15 at 2:00
source share

For iOS9 and later, textview even on viewWillAppear: comes with CGRect (0,0,1000,1000). For this to work, you need to call viewWillAppear:

 [self.view setNeedsLayout]; [self.view layoutIfNeeded]; // * Your code here 

After that, the text view will have the correct CGRect data, and you can perform any scroll operation that you may need.

+6
Oct 10 '16 at 9:44
source share

The problem with putting code in viewDidLayoutSubviews and viewWillLayoutSubviews is that these methods are called a lot (during device rotation, resizing, etc.). If you read something from a text view and rotate the device, you expect some of the content you are viewing to remain on the screen. You do not expect it to scroll up. Instead of scrolling up the content, try keeping the scrollEnabled property in the text view set to NO (false) and re-enable it in viewDidAppear.

+2
Oct 30 '17 at 18:56
source share

If you do not want to spoil the restrictions:

 override func updateViewConstraints() { super.updateViewConstraints() } override func viewDidLayoutSubviews() { self.textLabel.setContentOffset(CGPointZero, animated: false) } 
+1
Mar 21 '16 at 2:49 on
source share

This is an interesting mistake. In our project, this only happens on devices with an iPhone 5 -size screen. It seems that textOffset contentOffset changes at some point during the life of the view controller. In viewDidLoad and viewWillAppear textual representation of contentOffset is 0,0 , and with viewDidAppear it has changed. You can see it in viewWillLayoutSubviews . The restrictions seem to be set correctly.

This ensures that you do not call the scroll method if it is not needed:

 if textView.contentOffset.y > 0 { textView.contentOffset = CGPoint(x: 0, y: 0) // Or use scrollRectToVisible, scrollRangeToVisible, etc. } 
+1
Feb 20 '18 at 15:33
source share

This works differently for me, I tried all the things mentioned above, but none of them worked in func viewWillAppear(_ animated: Bool) . Which ultimately makes textView scroll up, and in func viewDidAppear(_ animated: Bool) it scrolls after the screen appears.

The below worked for me, but got some limitations related to the keyboard up and down.

 override func viewDidLayoutSubviews() { self.textView.setContentOffset(.zero, animated: false) } 

The below worked as expected:

 override func viewDidLoad() { super.viewDidLoad() self.textView.scrollsToTop = true } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.view.layoutIfNeeded() self.textView.setContentOffset(.zero, animated: false) } 
+1
Jun 07 '19 at 7:07
source share

swift

 override func viewDidLoad() { super.viewDidLoad() textView.isScrollEnabled = false } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) textView.isScrollEnabled = true } 
0
Feb 22 '19 at 8:26
source share

It seems like a terrible idea to solve this problem in the code in the view controller, because: A. The view controller makes no mistakes or does something wrong, and B, if you have more than one view controller with incorrectly scrolled text, you will end up the result with redundant code. The solution should be to write code that exists in the text view class. My solution works with Interface Builder, where I just select a custom class for a UITextView and use this class:

 import Foundation import UIKit class TopTextView: UITextView { var scrolled = false override func layoutSubviews() { super.layoutSubviews() if scrolled { return } setContentOffset(.zero, animated: false) scrolled = true } } 

It worked for me. I happened to have a view controller with a child view with a UITextView as a child of this view, and not with a UITextView as a child of the view controller. I don’t know how well this works if the text view is under the top or bottom bars, but since no inserts are affected, this should work.

0
Sep 05 '19 at 16:30
source share



All Articles