103

好的,我遇到了一些问题UITextView。这是问题:

我将一些文本添加到UITextView. 然后用户双击以选择一些东西。然后我更改UITextView(以编程方式如上)中的文本并将UITextView 滚动到有光标的页面底部。

但是,这不是用户点击的地方。UITextView无论用户点击哪里,它总是滚动到底部。

UITextView所以这是我的问题:每次更改文本时如何强制滚动到顶部?我试过contentOffsetscrollRangeToVisible。都不工作。

任何建议,将不胜感激。

4

37 回答 37

154
UITextView*note;
[note setContentOffset:CGPointZero animated:YES];

这对我有用。

Swift 版本(Xcode 9.3 上带有 iOS 11 的 Swift 4.1):

note.setContentOffset(.zero, animated: true)
于 2010-04-01T03:02:01.863 回答
70

如果有人在 iOS 8 中遇到此问题,我发现只需设置UITextView'stext 属性,然后scrollRangeToVisible使用NSRangewith location:0,调用即可length:0。我的文本视图不可编辑,我测试了可选择和不可选择(两种设置都不会影响结果)。这是一个斯威夫特的例子:

myTextView.text = "Text that is long enough to scroll"
myTextView.scrollRangeToVisible(NSRange(location:0, length:0))
于 2015-03-02T01:19:59.417 回答
46

这是我的解决方案...

    override func viewDidLoad() {
        textView.scrollEnabled = false
        textView.text = "your text"
    }

    override func viewDidAppear(animated: Bool) {
        textView.scrollEnabled = true
    }
于 2015-07-23T21:13:06.797 回答
39

打电话

scrollRangeToVisible(NSMakeRange(0, 0))

工作,但调用它

override func viewDidAppear(animated: Bool)
于 2015-05-13T09:33:10.283 回答
29

我在 HTML 中使用属性字符串,文本视图不可编辑。设置内容偏移量对我也不起作用。这对我有用:禁用滚动启用,设置文本,然后再次启用滚动

[yourTextView setScrollEnabled:NO];
yourTextView.text = yourtext;
[yourTextView setScrollEnabled:YES];
于 2014-10-16T00:06:29.490 回答
19

由于这些解决方案都不适合我,而且我浪费了太多时间拼凑解决方案,这终于为我解决了。

override func viewWillAppear(animated: Bool) {
    dispatch_async(dispatch_get_main_queue(), {
        let desiredOffset = CGPoint(x: 0, y: -self.textView.contentInset.top)
        self.textView.setContentOffset(desiredOffset, animated: false)
    })
}

这真的很愚蠢,这不是此控件的默认行为。

我希望这对其他人有所帮助。

于 2016-01-18T22:15:11.943 回答
18

I'm not sure if I understand your question, but are you trying to simply scroll the view to the top? If so you should do

[textview scrollRectToVisible:CGRectMake(0,0,1,1) animated:YES];

于 2009-08-06T19:08:03.470 回答
14

对于 iOS 10 和 Swift 3,我做了:

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

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

为我工作,不确定您是否遇到最新版本的 Swift 和 iOS 的问题。

于 2016-11-01T17:12:59.123 回答
10

我有一个更新的答案,它将正确显示 textview,并且用户不会遇到滚动动画。

override func viewWillAppear(animated: Bool) {
    dispatch_async(dispatch_get_main_queue(), {
        self.introductionText.scrollRangeToVisible(NSMakeRange(0, 0))
    })
于 2015-10-16T22:52:13.233 回答
10

这就是它在 iOS 9 Release 上的工作方式,以便 textView 在出现在屏幕上之前滚动到顶部

- (void)viewDidLoad
{
    [super viewDidLoad];
    textView.scrollEnabled = NO;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    textView.scrollEnabled = YES;
}
于 2015-09-21T11:03:12.613 回答
9

我就是这样做的

斯威夫特 4:

extension UITextView {

    override open func draw(_ rect: CGRect)
    {
        super.draw(rect)
        setContentOffset(CGPoint.zero, animated: false)
    }

 }
于 2018-04-16T12:38:43.263 回答
8

这对我有用

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    DispatchQueue.main.async {
      self.textView.scrollRangeToVisible(NSRange(location: 0, length: 0))
    }
  }
于 2018-08-10T18:07:18.790 回答
6

试试这个将光标移动到文本的顶部。

NSRange r  = {0,0};
[yourTextView setSelectedRange:r];

看看情况如何。确保在所有事件都已触发或您正在做的事情完成后调用它。

于 2009-08-06T02:14:51.997 回答
6

我不得不在 viewDidLayoutSubviews 内部调用以下内容在 viewDidLoad 内部调用太早了):

    myTextView.setContentOffset(.zero, animated: true)
于 2019-05-08T13:27:30.057 回答
6

只是你可以使用这个代码

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    textView.scrollRangeToVisible(NSMakeRange(0, 0))
}
于 2018-02-23T08:54:14.177 回答
6

我的问题是将 textView 设置为在视图出现时滚动到顶部。适用于 iOS 10.3.2 和 Swift 3。

解决方案1:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // It doesn't work. Very strange.
    self.textView.setContentOffset(CGPoint.zero, animated: false)
}
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // It works, but with an animation effection.
    self.textView.setContentOffset(CGPoint.zero, animated: false)
}

解决方案2:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    // It works.       
    self.textView.contentOffset = CGPoint.zero
}
于 2017-06-02T02:48:58.510 回答
5
[txtView setContentOffset:CGPointMake(0.0, 0.0) animated:YES];

这行代码对我有用。

于 2011-02-01T01:19:24.293 回答
5

结合以前的答案,现在它应该可以工作了:

talePageText.scrollEnabled = false
talePageText.textColor = UIColor.blackColor()
talePageText.font = UIFont(name: "Bradley Hand", size: 24.0)
talePageText.contentOffset = CGPointZero
talePageText.scrollRangeToVisible(NSRange(location:0, length:0))
talePageText.scrollEnabled = true
于 2015-04-02T12:53:27.703 回答
4

在斯威夫特 3 中:

  • viewWillLayoutSubviews是进行更改的地方。viewWillAppear应该也可以工作,但从逻辑上讲,布局应该在viewWillLayoutSubviews中执行。

  • 关于方法,scrollRangeToVisiblesetContentOffset都可以。但是,setContentOffset允许关闭或打开动画。

假设UITextView被命名为yourUITextView。这是代码:

// Connects to the TextView in the interface builder.
@IBOutlet weak var yourUITextView: UITextView!

/// Overrides the viewWillLayoutSubviews of the super class.
override func viewWillLayoutSubviews() {

    // Ensures the super class is happy.
    super.viewWillLayoutSubviews()

    // Option 1:
    // Scrolls to a range of text, (0,0) in this very case, animated.
    yourUITextView.scrollRangeToVisible(NSRange(location: 0, length: 0))

    // Option 2:
    // Sets the offset directly, optional animation.
    yourUITextView.setContentOffset(CGPoint(x: 0, y: 0), animated: false)
}
于 2017-02-27T03:46:26.347 回答
4

斯威夫特 2 答案:

textView.scrollEnabled = false

/* Set the content of your textView here */

textView.scrollEnabled = true

这可以防止 textView 在设置后滚动到文本的末尾。

于 2016-04-01T08:16:29.560 回答
3
-(void) viewDidAppear:(BOOL)animated{
[mytextView scrollRangeToVisible:NSMakeRange(0,0)];}

- (void)viewWillAppear:(BOOL)animated{
[mytextView scrollRangeToVisible:NSMakeRange(0,0)];}
  • ViewWillappear会在用户注意到之前立即执行此操作,但ViewDidDisappear部分会懒惰地对其进行动画处理。
  • [mytextView setContentOffset:CGPointZero animated:YES];有时不起作用(我不知道为什么),所以请改用 scrollrangetovisible 。
于 2016-06-09T21:48:50.880 回答
3
-(void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];

    [textview setContentOffset:CGPointZero animated:NO];
}
于 2016-04-24T05:56:15.863 回答
3

这对我有用。它基于 RyanTCBs 的回答,但它是同一解决方案的 Objective-C 变体:

- (void) viewWillAppear:(BOOL)animated {
    // For some reason the text view, which is a scroll view, did scroll to the end of the text which seems to hide the imprint etc at the beginning of the text.
    // On some devices it is not obvious that there is more text when the user scrolls up.
    // Therefore we need to scroll textView to the top.
    [self.textView scrollRangeToVisible:NSMakeRange(0, 0)];
}
于 2015-12-15T22:34:11.390 回答
2
[self.textView scrollRectToVisible:CGRectMake(0, 0, 320, self.textView.frame.size.height) animated:NO];
于 2015-05-25T08:54:45.147 回答
2

我遇到了问题,但在我的情况下,textview 是一些自定义视图的子视图并将其添加到 ViewController。没有一个解决方案对我有用。为了解决这个问题,添加了 0.1 秒的延迟,然后启用了滚动。它对我有用。

textView.isScrollEnabled = false
..
textView.text = // set your text here

let dispatchTime = DispatchTime.now() + 0.1
DispatchQueue.main.asyncAfter(deadline: dispatchTime) {
   self.textView.isScrollEnabled = true
}
于 2017-02-27T13:45:12.793 回答
2

问题解决:iOS = 10.2 Swift 3 UITextView

我刚刚使用了以下行:

displayText.contentOffset.y = 0
于 2017-01-14T02:34:57.853 回答
1

对我来说,这段代码很好用:

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

    //this part of code scrolls to top
    textView.contentOffset.y = -64
    textView.scrollEnabled = false
    textView.layoutIfNeeded() //if don't work, try to delete this line
    textView.scrollEnabled = true

为了滚动到确切位置并将其显示在屏幕顶部,我使用以下代码:

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

设置 contentOffset.y 滚动到文本的末尾,然后 scrollRangeToVisible 滚动到 scrollToLocation 的值。因此,需要的位置出现在 scrollView 的第一行。

于 2015-12-07T15:59:13.443 回答
1

尝试使用这 2 行解决方案:

view.layoutIfNeeded()
textView.contentOffset = CGPointMake(textView.contentInset.left, textView.contentInset.top)
于 2016-05-24T14:49:26.010 回答
1

对我来说,在 iOS 9 中,它停止为我使用带有方法 scrollRangeToVisible 的属性字符串(第 1 行使用粗体字体,其他行使用常规字体)

所以我不得不使用:

textViewMain.attributedText = attributedString
textViewMain.scrollRangeToVisible(NSRange(location:0, length:0))
delay(0.0, closure: { 
                self.textViewMain.scrollRectToVisible(CGRectMake(0, 0, 10, 10), animated: false)
            })

延迟是:

func delay(delay:Double, closure:()->Void) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}
于 2016-04-27T08:33:35.603 回答
1

这段代码解决了这个问题,也有助于避免不必要的自动滚动到 textView 的末尾。只需使用方法setTextPreservingContentOffset:而不是直接将文本设置为 textView。

@interface ViewController () {
    __weak IBOutlet UITextView *textView;
    CGPoint lastContentOffset;
    NSTimer *autoscrollTimer;
    BOOL revertAnyContentOffsetChanges;
}

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [textView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}

- (void)dealloc
{
    [textView removeObserver:self forKeyPath:@"contentOffset"];
}

- (void)setTextPreservingContentOffset:(NSString *)text
{
    lastContentOffset = textView.contentOffset;
    [autoscrollTimer invalidate];
    revertAnyContentOffsetChanges = YES;
    textView.text = text;
    autoscrollTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(enableScrolling:) userInfo:nil repeats:NO];
    autoscrollTimer.tolerance = 1;
}

- (void)enableScrolling:(NSTimer *)timer
{
    revertAnyContentOffsetChanges = NO;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (revertAnyContentOffsetChanges && [keyPath isEqualToString:@"contentOffset"] && [[change valueForKey:@"new"] CGPointValue].y != lastContentOffset.y) {
        [textView setContentOffset:lastContentOffset animated:NO];
    }
}

@end
于 2018-05-21T12:34:02.007 回答
1

我认为有些人遇到这个问题的原因是因为他们试图在滚动位置出现 TextView之前设置滚动位置。TextView

TextView当尚未出现时,没有什么可滚动的。

您需要先等待TextView出现,然后才能在viewDidAppear方法中设置其滚动位置,如下所示:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    textView.setContentOffset(CGPoint.zero, animated: false)
}
于 2018-01-01T21:15:07.330 回答
1

Swift 3 版本的draw_s 答案较早,这是在尝试了大多数其他答案之后唯一对我有用的东西。

    override func viewWillAppear(_ animated: Bool) {
    DispatchQueue.main.async{
        let desiredOffset = CGPoint(x: 0, y: -self.person_description.contentInset.top)
        self.person_description.setContentOffset(desiredOffset, animated: false)
    }
}

这是工作代码的剪切和粘贴。将 person_description 替换为您的 textview 变量。

于 2017-09-14T09:18:10.873 回答
1

textview 的默认行为是滚动到底部,因为它使用户能够继续编辑。

将 textview 偏移设置为其 inset 的最大值为我解决了这个问题。

override func viewDidLayoutSubviews() {  
    super.viewDidLayoutSubviews()  
    self.myTextView.contentOffset.y = -self.myTextView.contentInset.top  
}

注意:我的 textView 嵌入在导航控制器中。

于 2019-09-25T04:57:37.520 回答
1

这是我的代码。它工作正常。

class MyViewController: ... 
{
  private offsetY: CGFloat = 0
  @IBOutlet weak var textView: UITextView!
  ...

  override viewWillAppear(...) 
  {
      ...
      offsetY = self.textView.contentOffset.y
      ...
  }
  ...
  func refreshView() {
      let offSetY = textView.contentOffset.y
      self.textView.setContentOffset(CGPoint(x:0, y:0), animated: true)
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
        [unowned self] in
        self.textView.setContentOffset(CGPoint(x:0, y:self.offSetY), 
           animated: true)
        self.textView.setNeedsDisplay()
      }
  }
于 2017-06-14T01:16:37.697 回答
0

一旦我在重新启用滚动之前添加了短暂的延迟,ChallengerGuy 的回答就完全解决了我的问题。在添加延迟之前,我的 PageController 页面都是固定的,除了第一页,在任何用户与页面交互后也会自行修复。添加延迟也修复了第一页的 UITextView 滚动位置。

override open func viewDidLoad() {
    super.viewDidLoad()
    textView.isScrollEnabled = false
    textView.text = textToScroll            
   ... other stuff
}

override open func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    Central().delay(0.5) {
        self.textView.isScrollEnabled = true
    }
}

(我的 Central() 文件中的延迟函数。)

func delay(_ delay: Double, closure:@escaping ()->()) {
    DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
        closure()
    }
}
于 2018-01-06T20:07:27.187 回答
0

对于 Swift,我认为最干净的方法是继承 UITextView 并使用这个小技巧

import UIKit

class MyTextView: UITextView {
    override var text: String! {
        willSet {
            isScrollEnabled = false
        } didSet {
            isScrollEnabled = true
        }
    }
}
于 2018-10-17T09:30:49.743 回答
-1

Xcode 8.0 的解决方案。斯威夫特 2.3。适用于界面构建,可以轻松修改为以编程方式工作。

class MBTextView: UITextView
{
    required init?(coder aDecoder: NSCoder)
    {
        super.init(coder: aDecoder)
        setupView()
    }

    func setupView() {}
}

class MBStartFromTopTV: MBTextView
{
    override func setupView()
    {
        // some custom code
    }

    override func drawRect(rect: CGRect)
    {
        super.drawRect(rect)
        setContentOffset(CGPoint.zero, animated: false)
    }
}
于 2016-12-15T19:57:16.110 回答