Как заставить UITextView прокручивать вверх до каждого раза при изменении текста?

Хорошо, у меня проблемы с UITextView. Здесь проблема:

Я добавляю текст в UITextView. Затем пользователь дважды щелкает, чтобы выбрать что-то. Затем я изменяю текст в UITextView (программно, как указано выше), а UITextView прокручивается в нижней части страницы, где есть курсор.

Однако это НЕ, где пользователь нажал. Он ВСЕГДА прокручивается в нижней части UITextView независимо от того, где пользователь нажал.

Итак, вот мой вопрос: как заставить UITextView прокручивать вверх до каждого раза при изменении текста? Я пробовал contentOffset и scrollRangeToVisible. Ни одна из них не работает.

Любые предложения будут оценены.

Ответ 1

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

Это делает это для меня.

Версия Swift (Swift 4.1 с iOS 11 на Xcode 9.3):

note.setContentOffset(.zero, animated: true)

Ответ 2

Если у кого-то есть эта проблема в iOS 8, я обнаружил, что просто установка свойства текста UITextView's, а затем вызов scrollRangeToVisible с помощью NSRange с location:0, length:0 работал. Мое текстовое представление не редактировалось, и я тестировал как выборочный, так и не выбираемый (ни одна из них не влияла на результат). Вот пример Swift:

myTextView.text = "Text that is long enough to scroll"
myTextView.scrollRangeToVisible(NSRange(location:0, length:0))

Ответ 3

И вот мое решение...

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

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

Ответ 4

Вызов

scrollRangeToVisible(NSMakeRange(0, 0))

работает, но назовите его

override func viewDidAppear(animated: Bool)

Ответ 5

Я использовал атрибутString в HTML с открытым текстом. Установка смещения содержимого тоже не работала для меня. Это сработало для меня: отключить прокрутку, установить текст, а затем снова включить прокрутку

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

Ответ 6

Поскольку ни один из этих решений не работал у меня, и я потратил слишком много времени на сбор решений, это, в конечном итоге, решило это для меня.

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

Я не уверен, понимаю ли я ваш вопрос, но пытаетесь ли вы просто прокрутить представление до вершины? Если это так, вы должны сделать

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

Ответ 8

Для 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.

Ответ 9

У меня есть обновленный ответ, который будет правильно отображаться в тексте, и без использования пользовательской анимации прокрутки.

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

Ответ 10

Вот как это работает в выпуске iOS 9 так как textView прокручивается сверху, прежде чем появляться на экране

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

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

Ответ 11

Вот как я это сделал

Свифт 4:

extension UITextView {

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

 }

Ответ 12

Попробуйте переместить курсор в начало текста.

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

Посмотрите, как это происходит. Убедитесь, что вы вызвали это после того, как все ваши события были уволены или что вы делаете.

Ответ 13

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

Эта строка кода работает для меня.

Ответ 14

Объединив предыдущие ответы, теперь он должен работать:

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

Моя проблема заключается в том, чтобы 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
}

Ответ 16

Swift 2 Ответ:

textView.scrollEnabled = false

/* Set the content of your textView here */

textView.scrollEnabled = true

Это предотвращает прокрутку текста в конце текста после его установки.

Ответ 17

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

Ответ 18

Это сработало для меня. Он основан на ответе 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)];
}

Ответ 19

-(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

Проблема решена: iOS = 10,2 Swift 3 UITextView

Я использовал только следующую строку:

displayText.contentOffset.y = 0

Ответ 21

просто вы можете использовать этот код

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

Ответ 22

Это сработало для меня

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

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

Ответ 23

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

Ответ 24

-(void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];

    [textview setContentOffset:CGPointZero animated:NO];
}

Ответ 25

У меня возникла проблема, но в моем случае 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
}

Ответ 26

Для меня отлично работает этот код:

    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.

Ответ 27

Для меня в 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)
            })

где delay:

func delay(delay:Double, closure:()->Void) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

Ответ 28

Попробуйте использовать это решение из 2 строк:

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

Ответ 29

Вот мои коды. Он отлично работает.

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

Ответ 30

Swift 3 version of 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.