UITextView is not scrolled to top when loaded

IosAutolayoutUitextview

Ios Problem Overview


When I have text that does not fill the UITextView, it is scrolled to the top working as intended. When there is more text than will fit on screen, the UITextView is scrolled to the middle of the text, rather than the top.

Here are some potentially relevant details:

In viewDidLoad to give some padding on top and bottom of UITextView:

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

The UITextView uses auto layout to anchor it 20px from top, bottom and each side of the screen (done in IB) to allow for different screen sizes and orientations.

I can still scroll it with my finger once its loaded.

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

Ios Solutions


Solution 1 - Ios

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

Swift 3

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

Swift 2.1

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

Objective C

- (void)viewDidLayoutSubviews {
    [self.mainTextView setContentOffset:CGPointZero animated:NO];
}

Solution 2 - Ios

UITextView is a subclass of UIScrollView, so you can use its methods. If all you want to do is ensure that it's scrolled to the top, then wherever the text is added try:

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

EDIT: AutoLayout with any kind of scrollview gets wonky fast. That setting a fixed width solves it isn't surprising. If it doesn't work in -viewDidLayoutSubviews then that is odd. Setting a layout constraint manually may work. First create the constraints in IB:

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

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];
        }

May still be necessary to setContentOffset in -viewDidLayoutSubviews.

(Another method would be to create a layout constraint for "'equal' widths" and "'equal' heights" between the textView and its superView, with a constant of "-40". It's only 'equal' if the constant is zero, otherwise it adjusts by the constant. But because you can only add this constraint to a view that constraints both views, you can't do this in IB.)

You may ask yourself, if I have to do this, what's the point of AutoLayout? I've studied AutoLayout in depth, and that is an excellent question.

Solution 3 - Ios

Swift

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

Objective-C

[self.textView scrollRangeToVisible:(NSMakeRange(0, 0))];

Solution 4 - Ios

i had same issue! Reset to suggested constrains 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)
    }

Solution 5 - Ios

For iOS9 and later the textview even on viewWillAppear: is coming with CGRect(0,0,1000,1000). In order for this to work you have to call in viewWillAppear:

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

After that the textview will have correct CGRect data and you can perform any scrolling operation you may need.

Solution 6 - Ios

The problem with putting code in viewDidLayoutSubviews and viewWillLayoutSubviews is that these methods are called a lot (during device rotation, resizing views etc ...). If you're reading something from text view, and you rotate the device, you expect that the part of the content you're viewing stays on screen. You do not expect that it scrolls back to top. Instead of scrolling the content to top, try to keep text view's scrollEnabled property set to NO (false), and turn it back on in viewDidAppear.

Solution 7 - Ios

If you don't wanna mess with constraints:

override func updateViewConstraints() {
    super.updateViewConstraints()
}

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

Solution 8 - Ios

This is an interesting bug. In our project, this is only occurring on devices with an iPhone 5-size screen. It appears that the textview contentOffset changes at some point during the view controller lifecycle. In viewDidLoad and viewWillAppear the textview's contentOffset is 0,0, and by viewDidAppear it's changed. You can see it happening in viewWillLayoutSubviews. Constraints appear to be set up correctly.

This will ensure you don't call a scrolling method unless it's needed:

if textView.contentOffset.y > 0 {
    textView.contentOffset = CGPoint(x: 0, y: 0)
    // Or use scrollRectToVisible, scrollRangeToVisible, etc.
}

Solution 9 - Ios

Swift

override func viewDidLoad() {
    super.viewDidLoad()  
    textView.isScrollEnabled = false  
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    textView.isScrollEnabled = true
}

Solution 10 - Ios

For me this works in a different way, I tried all things mentioned above but none of the worked in func viewWillAppear(_ animated: Bool). Which eventually makes textView scrolled up, and in func viewDidAppear(_ animated: Bool) it would scroll after screen appeared.

Below worked for me but got some constraint related issue with keyboard up and down.

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

Below worked as expectation:

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)
}

Solution 11 - Ios

David Rectors answer in Objective C:

#import "TopTextView.h"

@implementation TopTextView

bool scrolled = NO;

- (void) layoutSubviews
{
    [super layoutSubviews];
    if (!scrolled) {
        [self setContentOffset:CGPointMake(0, 0) animated:NO];
        scrolled = YES;
    }
}

@end

Solution 12 - Ios

It seems like a terrible idea to handle this issue in code in the view controller because: A. The view controller isn't making any mistake or doing anything wrong, and B, if you have more than one view controller with a wrongly scrolled text view, you end up 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 simply select a custom class for the 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
	}
}

This worked for me. I happen to have a view controller with a child view with a UITextView as a child of that view, not with a UITextView as the child of the view controller. I don't know how well this works if the text view is under top or bottom bars but since no edge insets are touched, this should work.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMichael CampsallView Question on Stackoverflow
Solution 1 - IosMuhammad IbrahimView Answer on Stackoverflow
Solution 2 - IosMike SandView Answer on Stackoverflow
Solution 3 - IosAlessandroDPView Answer on Stackoverflow
Solution 4 - IosRusoView Answer on Stackoverflow
Solution 5 - IosiPavView Answer on Stackoverflow
Solution 6 - IosJovan StankovicView Answer on Stackoverflow
Solution 7 - IosGustavo SeveroView Answer on Stackoverflow
Solution 8 - IosEvan RView Answer on Stackoverflow
Solution 9 - IosБорис ЛысенкоView Answer on Stackoverflow
Solution 10 - IosSwapnil DhotreView Answer on Stackoverflow
Solution 11 - IosniclasView Answer on Stackoverflow
Solution 12 - IosDavid RectorView Answer on Stackoverflow