UITextView 在加载时不会滚动到顶部



当我有文本没有填满UITextView时,它会按预期滚动到顶部工作。当文本多于屏幕上可容纳的文本时,UITextView 将滚动到文本的中间,而不是顶部。

以下是一些潜在的相关详细信息:

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

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

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

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

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

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

斯威夫特 3

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

斯威夫特 2.1

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

目标C

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

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

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

编辑:具有任何类型的滚动视图的自动布局都会变得不稳定。设置固定宽度可以解决它并不奇怪。如果它在-viewDidLayoutSubviews不起作用,那就很奇怪了。手动设置布局约束可能会起作用。首先在 IB 中创建约束:

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

然后在视图控制器中

    -(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 中设置内容偏移量。

(另一种方法是在textView及其superView之间为"'相等'宽度"和"'相等'高度"创建一个布局约束,常量为"-40"。只有当常量为零时,它才是"相等"的,否则它会根据常量进行调整。但是,由于您只能将此约束添加到约束两个视图的视图中,因此无法在 IB 中执行此操作。

你可能会问自己,如果我必须这样做,自动布局的意义何在?我已经深入研究了AutoLayout,这是一个很好的问题。

Swift

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

目标-C

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

我遇到了同样的问题!重置为建议的约束,然后只需放置(y 偏移量)

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

对于 iOS9 及更高版本,即使在 viewWillAppear: 上的文本视图也随 CGRect(0,0,1000,1000) 一起出现。为了使它起作用,您必须调用viewWillAppear:

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

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

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

如果你不想弄乱约束:

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

这是一个有趣的错误。 在我们的项目中,这只发生在屏幕尺寸iPhone 5的设备上。 文本视图似乎contentOffset在视图控制器生命周期中的某个时间点发生变化。 在viewDidLoadviewWillAppear文本视图的contentOffset0,0的,并且通过viewDidAppear它被更改了。 你可以看到它发生在viewWillLayoutSubviews. 约束似乎设置正确。

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

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

斯威夫特

override func viewDidLoad() {
    super.viewDidLoad()  
    textView.isScrollEnabled = false  
}
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    textView.isScrollEnabled = true
}
对我来说

,这以不同的方式工作,我尝试了上面提到的所有事情,但没有一个在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)
}

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

在视图控制器的代码中处理此问题似乎是一个糟糕的主意,因为: A.视图控制器没有犯任何错误或做错任何事,而 B,如果您有多个视图控制器具有错误滚动的文本视图,您最终会得到冗余代码。解决方案应该是编写文本视图类中存在的代码。我的解决方案适用于界面生成器,我只需为 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 作为视图控制器的子视图。我不知道如果文本视图位于顶部或底部栏下方,这效果如何,但由于没有触及边缘插入,这应该有效。

就我而言,我必须这样做:

textView.setContentOffset(CGPoint(x: 0, y: -self.textView.adjustedContentInset.top), animated: false)

因为 Texview 位于导航栏下方,并且调整了插图

最新更新