79

I have a long text coming from my JSON file but when I click the link from my UITableViewCell to go to my UIViewController page, the UITextView text loads the string content but it does not show the content from the beginning and I have to scroll up all the time.

What I need to do?

Matthew Spencer
  • 2,265
  • 1
  • 23
  • 28
Ornilo
  • 791
  • 1
  • 5
  • 4
  • Have you tried setting the contentOffset to (0,0)? – rdelmar Nov 10 '14 at 03:37
  • You can edit this question. Below the tags you see 'edit'. click that to edit. I got a suggestion for an edit but feel the user should edit the question. – LanternMike Nov 11 '14 at 06:01
  • check out this page and see if one of these solutions works for you. Most everything on here is on there and more http://stackoverflow.com/questions/1234242/how-do-i-force-a-uitextview-to-scroll-to-the-top-every-time-i-change-the-text If you have questions be specific in what is going on, working, not working what you tried. – LanternMike Nov 11 '14 at 06:11
  • Here is the link with my problem: [link](http://www.ornilosantiago.com/ios/example.jpg) – Ornilo Nov 11 '14 at 06:40
  • the only solution that worked for me was from [this one](http://stackoverflow.com/a/28377727/2115904) from another post – Andrii Bas Oct 06 '15 at 14:43

22 Answers22

161

I had the same problem, and turns out I had to set the content offset in viewDidLayoutSubviews for it to take effect. I'm using this code to display attributed static text.

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

SWIFT 3:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    self.textView.setContentOffset(CGPoint.zero, animated: false)
}
andym
  • 67
  • 6
iosjillian
  • 2,118
  • 1
  • 14
  • 8
  • 4
    Of all the answers, this one works the best. In addition, if your UITextView text starts somewhere toward the vertical middle of the text view then adding the following to viewDidLoad will fix that too: self.automaticallyAdjustsScrollViewInsets = false – Wizkid Oct 04 '15 at 18:32
  • The interesting thing is, that offuttjillian's solution did work for me, but the solution given by you @Wizkid and Glenn makes it even worse for me on iOS 9.1 Anyway it's working now and that makes me happy^^ – Frozn Nov 01 '15 at 00:46
  • 2
    although this is a working solution unfortunately it has a big side effect the ugly visible upscroll even if you are using `viewWillLayoutSubviews` :/ – Hofi Mar 17 '16 at 11:30
  • Trying almost 6 ways for solving the issue, this answer only worked for me in iOS9.x. – KoreanXcodeWorker May 27 '16 at 10:50
  • works well even if set it after assigning text for UITextView – Hassy Oct 06 '16 at 12:10
  • `setContentOffset(CGPoint.zero, animated: false)` will lead to a hard-to-find bug: `layoutManager.boundingRect(forGlyphRange aRange, in container: textContainer)` return wrong frame – steveluoxin Sep 14 '19 at 05:42
46

This is the only way that worked for me. I disable the scroll of the UITextView before the view is loaded and then i enable it again:

  override func viewWillAppear(_ animated: Bool) {
        yourTextView.isScrollEnabled = false
    }

    override func viewDidAppear(_ animated: Bool) {
        yourTextView.isScrollEnabled = true
    }
DanielZanchi
  • 2,708
  • 1
  • 25
  • 37
27
[self.textView scrollRangeToVisible:NSMakeRange(0, 1)];

in viewDidLoad

Keith Smiley
  • 61,481
  • 12
  • 97
  • 110
Liuk Smith
  • 311
  • 3
  • 6
19

By Programmatically before loading the content disable the scrolling property of textview textview.scrollenabled = NO;

And after loading enable the scrolling of textview textview.scrollenabled = YES;

As well check the XIB, always non-check the scrolling enabled of Textview.

Kamar Shad
  • 6,089
  • 1
  • 29
  • 56
Subathra D
  • 389
  • 3
  • 7
13

The answers for the question Blank space at top of UITextView in iOS 10 provide a much cleaner end user experience.

In viewDidLoad of the view controller containing the text view:

 self.automaticallyAdjustsScrollViewInsets = false

Setting textView.setContentOffset(CGPointMake(0,0), animated: false) and some of these other suggestions do work when called in the viewDidLayoutSubviews() but on older devices like iPad 2 and older you will actually see the text get scrolled when the screen is displayed. That is not something you want the end user to see.

Community
  • 1
  • 1
Glenn
  • 189
  • 1
  • 9
4

I was still having problems after using these solutions. The problem definitely seems to relate to having transparent navigation bars and selecting to automatically adjust content insets on the view controller. If you don't care about your text scrolling underneath the navigation bar then it's best to leave these settings off and constrain the top of your textview to the bottom of the navigation bar, rather than to the top of the viewcontroller.

If like me you wanted it to appear underneath your navigation bar when you scroll down; then the solution that worked for me was to add this.

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];

    CGFloat offset = self.navigationController.navigationBar.frame.size.height+[UIApplication sharedApplication].statusBarFrame.size.height;

    [self.textView setContentOffset:CGPointMake(0, -offset) animated:NO];
}

This just looks for the height of the navigation bar and status bar and adjusts the content offset accordingly.

Note that one downside of this approach is that when the device rotates you'll end up scrolling back to the top.

Mark Bridges
  • 8,228
  • 4
  • 50
  • 65
4

For me fine works this code:

    textView.attributedText = newText //or textView.text = ...

    //this part of code scrolls to top
    textView.contentOffset.y = -64 //or = 0 if no Navigation Bar
    textView.scrollEnabled = false
    textView.layoutIfNeeded()
    textView.scrollEnabled = true

For scroll to exact position and show it on top of screen I use this code:

    var scrollToLocation = 50 //<needed position>
    textView.contentOffset.y = textView.contentSize.height
    textView.scrollRangeToVisible(NSRange.init(location: scrollToLocation, length: 1))

Setting contentOffset.y scrolls to the end of text, and then scrollRangeToVisible scrolls up to value of scrollToLocation. Thereby, needed position appears in first line of scrollView.

Igor
  • 12,165
  • 4
  • 57
  • 73
4

Similar to some other answers, but with the added benefit that you won't cause a scroll to top on subsequent device rotations. Works well in Swift 2.2

/// Whether view has laid out subviews at least once before.
var viewDidLayoutSubviewsAtLeastOnce = false

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if !viewDidLayoutSubviewsAtLeastOnce {
        textView.setContentOffset(CGPoint(x: 0, y: -textView.contentInset.top), animated: false)
    }

    viewDidLayoutSubviewsAtLeastOnce = true
}
danbretl
  • 644
  • 6
  • 14
  • After trying a few different answers this one worked the best for me. As per Swindler's answer, you could use CGPointZero for the CGPoint. – Mitch Downey Aug 28 '16 at 02:37
  • It is important to do this in this method - viewDidLayoutSubviews. Many answers will have you do this in viewWillAppear, but this is wrong. viewDidLayoutSubviews is the place to do this. Thanks. – geekyaleks Oct 13 '16 at 20:20
3

Swift Version

A combination of things will be needed:

1.) Set your outlet

  @IBOutlet var textView: UITextView!

2.) In storyboard on View Controller turn off "Adjust Scroll View Insets"

3.) Set content to zero top by adding below to your view controller

override func viewWillLayoutSubviews() {
   super.viewWillLayoutSubviews()
     myUITextView.setContentOffset(CGPointZero, animated: false)
}
kelsheikh
  • 1,278
  • 3
  • 17
  • 37
3

Instead of setting content offset from viewDidLayoutSubviews you can write layoutIfNeeded from viewDidLoad to set the proper position of textview as below:

    self.textView.layoutIfNeeded()
    self.textView.setContentOffset(CGPoint.zero, animated: false)

Cheers !!

Dhaval H. Nena
  • 3,992
  • 1
  • 37
  • 50
2

In Swift 2, Xcode 7 solution, to leave scroll Enabled as well as have the text start at the top, this is all you need:

@IBOutlet weak var myUITextView: UITextView!

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    //start scroll at top of text
    myUITextView.scrollRangeToVisible(NSMakeRange(0, 0))
}
Brian Ogden
  • 18,439
  • 10
  • 97
  • 176
  • 1
    thanks! this worked perfectly for me with Swift 2.2. None of the other solutions here worked as smoothy and simply. – Natalia Jun 04 '16 at 20:29
2

Swift 3.0

override func viewWillAppear(_ animated: Bool) {
    privacyText.isScrollEnabled = false
}

override func viewDidAppear(_ animated: Bool) {
    privacyText.isScrollEnabled = true
}
MRustamzade
  • 1,425
  • 14
  • 27
  • Disable scrolling in Storyboard! And enable in code. override func viewDidAppear(_ animated: Bool) { privacyText.isScrollEnabled = true } – Vitaliy A Sep 09 '17 at 21:27
2

This worked the best for me! I placed this within viewDidLoad().

//TextView Scroll starts from the top
myTextView.contentOffset.y = 0
Warren
  • 671
  • 6
  • 3
1

Here's another way to do it that always works for me. Objective-C:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self.textView setContentOffset:CGPointZero animated:NO];
}

And in Swift:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    textView.setContentOffset(CGPointZero, animated: false)
}
Swindler
  • 802
  • 10
  • 9
1

Swift version:

override func viewDidLayoutSubviews() {
    yourTextView.setContentOffset(CGPointZero, animated: false)
}
Rashwan L
  • 38,237
  • 7
  • 103
  • 107
1

Swift 3, 4, 5 solution:

Steps to solve the issue:

  • Disable the UITextView scroll
  • set scrollRectToVisible
  • enable UITextView scroll

Code:

yourTextView.isScrollEnabled = false
let rect:CGRect = CGRect(x: 0, y: 0, width: 1, height: 1)
yourTextView.scrollRectToVisible(rect, animated: false)
yourTextView.isScrollEnabled = true

This Worked for me. Hope that will help!

Mohit Kumar
  • 2,898
  • 3
  • 21
  • 34
1

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

或者 你在ViewDidAppear 里面加上滚动,这样用户会看到他往上滚动到第一行

myj
  • 11
  • 1
1

in swift 4 with attributed text any of answer does not help me and i combine some answers in topic.

override func viewWillAppear(_ animated: Bool) {
     super.viewWillAppear(animated)
     uiTextview.isScrollEnabled = false
}

override func viewDidAppear(_ animated: Bool) {
     uiTextview.isScrollEnabled = true
     uiTextview.setContentOffset(CGPoint.zero, animated: false)
}
hall.keskin
  • 201
  • 3
  • 6
0

This is how i did it. I subclassed textview, and:

override func willMoveToSuperview(newSuperview: UIView?) {
    self.scrollEnabled = false
}

override func layoutSubviews() {
    super.layoutSubviews()
    self.scrollEnabled = true
}
Tatarasanu Victor
  • 656
  • 1
  • 7
  • 19
0

From storyboard, select the view controller on which you have you text view placed. In the attributes inspector, uncheck "Adjust Scroll View Insets". That's it.

Aftab Baig
  • 279
  • 5
  • 16
0

Put this code on your class

override func viewDidLayoutSubviews() {
        self.About_TV.setContentOffset(.zero, animated: false) // About_TV : your text view name)
    }
Nimisha joshy
  • 326
  • 4
  • 6
-2

Add code to the viewdidload

self.automaticallyAdjustsScrollViewInsets = NO;
Eva Hsueh
  • 61
  • 1
  • 5