加载时UITextView不会滚动到顶部

时间:2015-01-20 18:59:07

标签: ios autolayout uitextview

当我的文本没有填满UITextView时,它会按预期滚动到顶部。如果文本上的文字多于屏幕上的文字,则UITextView会滚动到文本的中间位置,而不是顶部。

以下是一些可能相关的细节:

在viewDidLoad中为UITextView的顶部和底部提供一些填充:

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

UITextView使用自动布局将其从屏幕的顶部,底部和每一侧锚定20px(在IB中完成),以允许不同的屏幕尺寸和方向。

一旦加载,我仍然可以用手指滚动它。

EDIT 我发现删除自动布局约束然后修复宽度似乎只能解决问题,但仅限于该屏幕宽度。

12 个答案:

答案 0 :(得分:111)

将以下函数添加到视图控制器类...

Swift 3

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

Swift 2.1

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

目标C

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

答案 1 :(得分:18)

UITextView是UIScrollView的子类,因此您可以使用其方法。如果您只想确保它滚动到顶部,那么无论文本添加到何处,请尝试:

[self.mainTextView setContentOffset:CGPointZero animated:NO];
编辑:使用任何类型的滚动视图的AutoLayout变得非常快。固定宽度的设置解决了它并不令人惊讶。如果它在-viewDidLayoutSubviews中不起作用那么这很奇怪。手动设置布局约束可能有效。首先在IB中创建约束:

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

然后在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];
        }

-viewDidLayoutSubviews中的setContentOffset可能仍然需要。

(另一种方法是在textView之间创建"'宽度""'等高"高度"的布局约束和它的superView,常数为" -40"它只是等于'如果常数为零,否则它会根据常数调整。但是因为你只能将此约束添加到限制两个视图的视图中,您无法在IB中执行此操作。)

你可能会问自己,如果我必须这样做,那么AutoLayout的重点是什么?我已经深入研究了AutoLayout,这是一个很好的问题。

答案 2 :(得分:10)

<强>夫特

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

<强>目标C

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

答案 3 :(得分:9)

我有同样的问题!重置为建议的约束,然后只放(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)
    }

答案 4 :(得分:6)

对于iOS9及更高版本,即使在viewWillAppear上,textview也随附CGRect(0,0,1000,1000)。要使其工作,您必须在viewWillAppear中调用:

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

之后,textview将具有正确的CGRect数据,您可以执行任何可能需要的滚动操作。

答案 5 :(得分:2)

将代码置于viewDidLayoutSubviews和viewWillLayoutSubviews中的问题是这些方法被大量调用(在设备轮换期间,调整视图大小等...)。如果您正在从文本视图中读取内容并旋转设备,则您希望正在查看的内容部分保留在屏幕上。你不要指望它滚动到顶部。 不要将内容滚动到顶部,而是尝试将文本视图的scrollEnabled属性设置为NO(false),并在viewDidAppear中将其重新打开。

答案 6 :(得分:1)

如果你不想搞乱约束:

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

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

答案 7 :(得分:1)

这是一个有趣的错误。在我们的项目中,这仅发生在具有iPhone 5大小屏幕的设备上。看来,textview contentOffset在视图控制器生命周期中的某个时刻发生了变化。在viewDidLoadviewWillAppear中,textview&#39; contentOffset0,0viewDidAppear已更改。您可以在viewWillLayoutSubviews中看到它发生。约束似乎设置正确。

这将确保您不会调用滚动方法,除非需要:

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

答案 8 :(得分:1)

对我来说,这以不同的方式起作用,我尝试了上面提到的所有方法,但是func viewWillAppear(_ animated: Bool)中没有任何方法起作用。最终使textView向上滚动,并在func viewDidAppear(_ animated: Bool)中在屏幕出现后滚动。

以下为我工作,但在键盘上下移动时遇到了一些与约束有关的问题。

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

以下工作符合预期:

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

答案 9 :(得分:1)

David Rectors在目标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

答案 10 :(得分:0)

快速

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

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

答案 11 :(得分:0)

在视图控制器中的代码中处理此问题似乎是一个可怕的主意,因为:A.视图控制器没有犯任何错误或做错了任何事情,以及B,如果您有多个带有视图控件的视图控制器,错误滚动文本视图,您将得到多余的代码。解决方案应该是编写存在于文本视图类中的代码。我的解决方案可与Interface Builder一起使用,其中我只需为UITextView选择一个自定义类并使用该类:

import Foundation
import UIKit

class TopTextView: UITextView {
    var scrolled = false

    override func layoutSubviews() {
        super.layoutSubviews()
        if scrolled { return }
        setContentOffset(.zero, animated: false)
        scrolled = true
    }
}

这对我有用。我碰巧有一个视图控制器,其子视图带有UITextView作为该视图的子视图,而不是UITextView作为该视图控制器的子视图。我不知道如果文本视图位于顶部或底部条形之下,效果如何,但是由于没有边缘边缘被触摸,因此应该可以。