每次更改文本时,如何强制UITextView滚动到顶部?

时间:2009-08-05 16:12:03

标签: iphone ios uitextview

好的,我在使用UITextView时遇到了一些问题。这是问题所在:

我向UITextView添加了一些文字。然后用户双击以选择某些内容。 然后我将UITextView中的文本(以编程方式如上所述)和UITextView滚动更改为有光标的页面底部。

但是,这不是用户点击的地方。无论用户点击何处,它始终滚动到UITextView的底部。

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

任何建议都将不胜感激。

37 个答案:

答案 0 :(得分:142)

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

这对我有用。

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

note.setContentOffset(.zero, animated: true)

答案 1 :(得分:66)

如果有任何人在iOS 8中遇到此问题,我发现只需设置UITextView's文字属性,然后使用scrollRangeToVisible NSRange调用location:0,{{1工作。我的文本视图不可编辑,我测试了可选择的和不可选择的(两个设置都没有影响结果)。这是一个Swift示例:

length:0

答案 2 :(得分:41)

这是我的解决方案......

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

    override func viewDidAppear(animated: Bool) {
        textView.scrollEnabled = true
    }

答案 3 :(得分:36)

致电

scrollRangeToVisible(NSMakeRange(0, 0))

可以使用,但可以在

中调用它
override func viewDidAppear(animated: Bool)

答案 4 :(得分:29)

我在HTML中使用了attributionString,文本视图不可编辑。设置内容偏移对我来说也不起作用。这对我有用:禁用启用滚动,设置文本然后再次启用滚动

[yourTextView setScrollEnabled:NO];
yourTextView.text = yourtext;
[yourTextView setScrollEnabled:YES];

答案 5 :(得分:17)

我不确定我是否理解您的问题,但您是否只想将视图滚动到顶部?如果是这样你应该做

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

答案 6 :(得分:17)

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

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

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

我希望这可以帮助其他人。

答案 7 :(得分:11)

对于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的问题。

答案 8 :(得分:10)

我有一个更新的答案,它会使textview正确显示,并且没有用户体验滚动动画。

override func viewWillAppear(animated: Bool) {
    dispatch_async(dispatch_get_main_queue(), {
        self.introductionText.scrollRangeToVisible(NSMakeRange(0, 0))
    })

答案 9 :(得分:8)

这就是iOS 9 Release的工作原理 因此,在出现在屏幕上之前,textView会滚动到顶部

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

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    textView.scrollEnabled = YES;
}

答案 10 :(得分:7)

我是怎么做到的

斯威夫特4:

extension UITextView {

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

 }

答案 11 :(得分:5)

[txtView setContentOffset:CGPointMake(0.0, 0.0) animated:YES];

这行代码适合我。

答案 12 :(得分:5)

我的问题是在视图出现时将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
}

答案 13 :(得分:5)

尝试此操作将光标移动到文本的顶部。

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

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

答案 14 :(得分:4)

结合以前的答案,现在它应该有效:

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

答案 15 :(得分:4)

Swift 2答案:

textView.scrollEnabled = false

/* Set the content of your textView here */

textView.scrollEnabled = true

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

答案 16 :(得分:4)

在Swift 3中:

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

  • 关于方法, scrollRangeToVisible setContentOffset 都可以使用。但是, 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)
}

答案 17 :(得分: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)];
}

答案 18 :(得分:3)

这对我有用

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

    DispatchQueue.main.async {
      self.textView.scrollRangeToVisible(NSRange(location: 0, length: 0))
    }
  }

答案 19 :(得分: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。

答案 20 :(得分:3)

问题解决了: iOS = 10.2 斯威夫特3 的UITextView

我刚使用了以下一行:

displayText.contentOffset.y = 0

答案 21 :(得分:2)

只是你可以使用这段代码

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    textView.scrollRangeToVisible(NSMakeRange(0, 0))
}

答案 22 :(得分: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
}

答案 23 :(得分:2)

-(void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];

    [textview setContentOffset:CGPointZero animated:NO];
}

答案 24 :(得分:2)

[self.textView scrollRectToVisible:CGRectMake(0, 0, 320, self.textView.frame.size.height) animated:NO];

答案 25 :(得分: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

答案 26 :(得分:1)

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

view.layoutIfNeeded()
textView.contentOffset = CGPointMake(textView.contentInset.left, textView.contentInset.top)

答案 27 :(得分:1)

我必须在 viewDidLayoutSubviews 内部调用以下内容(在viewDidLoad内部调用还为时过早):

    myTextView.setContentOffset(.zero, animated: true)

答案 28 :(得分:1)

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

TextView尚未出现时,无法滚动。

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

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    textView.setContentOffset(CGPoint.zero, animated: false)
}

答案 29 :(得分:1)

之前的Swift 3版本的drew_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变量。

答案 30 :(得分: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()
      }
  }

答案 31 :(得分: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)
}

答案 32 :(得分: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的第一行。

答案 33 :(得分: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()
    }
}

答案 34 :(得分:0)

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

import UIKit

class MyTextView: UITextView {
    override var text: String! {
        willSet {
            isScrollEnabled = false
        } didSet {
            isScrollEnabled = true
        }
    }
}

答案 35 :(得分:0)

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

将textview偏移设置为其插图的最高值将为我解决该问题。

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

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

答案 36 :(得分:-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)
    }
}
相关问题