2015-10-30 4 views
13

Я сделал кнопку, которая добавляет некоторый текст в textView, и я хочу, чтобы она автоматически прокручивалась вниз, когда она была нажата, чтобы пользователь мог видеть добавленный новый текст.
Я не могу использовать решение this в Swift, потому что я не знаю Objective-C. Кто-нибудь знает, как я могу прокручивать нижнюю часть текста в Swift? Благодарю.Прокрутите до конца текстовый файл

+0

если 'textView' прокручивать вы можете прокручивать? Что именно вы имеете в виду? Вы пробовали это до публикации? Покажите какой-нибудь код :) – Korpel

+0

какая версия os вы используете? – PK20

+0

'self.textView.scrollRangeToVisible (NSMakeRange (0, 0))' попробуйте, где для диапазона положить конец 'textView' – Korpel

ответ

4

Так что, если вы нажмете на ссылку вы отправившим принятый ответ показывает эту Objective-C код:

-(void)scrollTextViewToBottom:(UITextView *)textView 
{ 
    if(textView.text.length > 0) 
    { 
    NSRange bottom = NSMakeRange(textView.text.length -1, 1); 
    [textView scrollRangeToVisible:bottom]; 
    } 
} 

Так что ваша задача состоит в том, чтобы преобразовать этот код Swift.

Разбивайте их на куски и обрабатывайте их по одному. Во-первых, определение самого метода.

Метод называется scrollTextViewToBottom. В качестве параметра он принимает UITextView и не возвращает результат. Как бы вы могли написать это определение метода в Swift?

Далее посмотрите, что тело метода. Оператор if должен быть точно таким же в Swift. Создание NSRange практически идентично. Вам просто нужно изменить его немного:

let bottom = NSMakeRange(textView.text.length -1, 1) 

Та часть, которая, вероятно, самым трудным для кого-то, кто не знает, Objective-C является вызов метода. Он отправляет сообщение scrollRangeToVisible на объект textView. Прошедший параметр: bottom. Посмотрите, можете ли вы переписать эту строку в Swift. Затем соедините все это.

+2

Итак, кто отказался от моего ответа и почему? Я пытаюсь научить OP как решать эти проблемы для себя, а не давать ему преобразованный код. В конечном итоге изучение того, как понять это для себя, гораздо более полезно, чем иметь что-то еще, что вы закончили код. –

+0

Я полностью согласен с вами. Сэр. Ваш ответ дает законные шаги, чтобы помочь OP.Upvoted – Korpel

+0

Я не согласен, это очень нестандартный способ прокрутки текстового вида. Большинство iOS наиболее знакомы с использованием 'contentOffset'. Не говоря уже о том, что 'NSRange', скорее всего, будет устаревшим в будущем в пользу Swift's Range. – barndog

0

UITextView имеет свойство contentOffsent. Вы можете либо установить textView.contentOffset или textView.setContentOffset(offset, animated: true)

Например, если contentSize вашего зрения текста является (100, 500), но высота зрения текста только 100, а затем перейдите к нижней, установите contentOffset свойство (0, 400) (это для вертикальный текстовый вид). В более общем виде формула для прокрутки вниз - textView.contentSize.height-textView.height. Каждый раз, когда вы нажимаете кнопку, установите смещение.

Я бы также рекомендовал прочитать документацию и попытаться понять ее. Swift и iOS достаточно хорошо документированы, и такой вопрос легко найти с помощью Google.

Редактировать: Это работает, потому что UITextView наследует от UIScrollView.

Sidenote: Я написал подкласс UITextView, где вы можете установить вертикальное выравнивание текста, поэтому, если вы установите выравнивание текста на .Bottom, текст будет выровнен в нижней части представления.

class TextView: UITextView { 

    enum VerticalAlignment: Int { 
     case Top = 0, Middle, Bottom 
    } 

    var verticalAlignment: VerticalAlignment = .Middle 

    //override contentSize property and observe using didSet 
    override var contentSize: CGSize { 
     didSet { 
      let textView = self 
      let height = textView.bounds.size.height 
      let contentHeight:CGFloat = contentSize.height 
      var topCorrect: CGFloat = 0.0 
      switch(self.verticalAlignment){ 
      case .Top: 
       textView.contentOffset = CGPointZero //set content offset to top 
      case .Middle: 
       topCorrect = (height - contentHeight * textView.zoomScale)/2.0 
       topCorrect = topCorrect < 0 ? 0 : topCorrect 
       textView.contentOffset = CGPoint(x: 0, y: -topCorrect) 
      case .Bottom: 
       topCorrect = textView.bounds.size.height - contentHeight 
       topCorrect = topCorrect < 0 ? 0 : topCorrect 
       textView.contentOffset = CGPoint(x: 0, y: -topCorrect) 
      } 
      if contentHeight >= height { //if the contentSize is greater than the height 
       topCorrect = contentHeight - height //set the contentOffset to be the 
       topCorrect = topCorrect < 0 ? 0 : topCorrect //contentHeight - height of textView 
       textView.contentOffset = CGPoint(x: 0, y: topCorrect) 
      } 
     } 
    } 

    // MARK: - UIView 

    override func layoutSubviews() { 
     super.layoutSubviews() 
     let size = self.contentSize //forces didSet to be called 
     self.contentSize = size 
    } 
} 

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

4

Просто, где является UITextView в вопрос:

let bottom = myTextView.contentSize.height 

myTextView.setContentOffset(CGPoint(x: 0, y: bottom), animated: true) // Scrolls to end 
14

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

В viewdidload:

self.storyTextView.layoutManager.allowsNonContiguousLayout = false 

Затем, когда это необходимо:

let stringLength:Int = self.storyTextView.text.characters.count 
self.storyTextView.scrollRangeToVisible(NSMakeRange(stringLength-1, 0)) 
3

Swift 4

let bottom = NSMakeRange(textLog.text.count - 1, 1) 
textLog.scrollRangeToVisible(bottom) 

Свифта 3

let bottom = NSMakeRange(textLog.text.characters.count - 1, 1) 
textLog.scrollRangeToVisible(bottom) 

Обновление: спасибо @AntoineRucquoy для Swift 4 напоминания!

+0

С Swift 4.x и во избежание устаревшего предупреждения используйте textLog.text.count, а не textLog.text.characters.count :-) –

0

Я использую следующие в приложение, которое прокручивается на дно автоматически добавляется текст:

Сначала при инициализации вашего TextView, сделать следующее:

textView.layoutManager.allowsNonContiguousLayout = false 
textView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil) 

Затем добавьте следующий метод наблюдателя:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 
    var bottom = textView.contentSize.height - textView.frame.size.height 
    if bottom < 0 { 
     bottom = 0 
    } 
    if textView.contentOffset.y != bottom { 
     textView.setContentOffset(CGPoint(x: 0, y: bottom), animated: true) 
    } 
} 

установка allowsNonContiguousLayout к ложным фиксированный контент. Проблемы для меня.

Добавление contentSize наблюдателя будет наблюдать за любые новые изменения в contentSize в TextView и вызовите функцию -observeValue (forKeyPath ...) при внесении изменений.

В -observeValue (...) функции, мы сначала получить нижней (у contentOffset когда полностью прокручивается на дно). Затем мы проверяем, является ли это значение отрицательным, что означает, что высота contentSize меньше высоты кадра textView, и вы не можете действительно прокручивать. Если вы попытаетесь программно прокрутить это отрицательное значение, это вызовет этот печально известный джиттер, который многие знают и любят. Поэтому, чтобы избежать этого дрожания, мы просто устанавливаем значение для того, что оно уже должно быть, или вы также можете просто return.

Тогда мы просто тест, чтобы увидеть, если contentOffset уже не равен нижней значения , мы даем ему, что новое значение. Это позволяет избежать установки contentOffset, когда его не нужно устанавливать.

0

Если вы имеете дело с attributedText имущества UITextView в:

в viewDidLoad()

self.storyTextView.layoutManager.allowsNonContiguousLayout = false 

в методе прокруткой

let stringLength:Int = self.storyTextView.attributedText.string.characters.count 
self.storyTextView.scrollRangeToVisible(NSMakeRange(stringLength-1, 0)) 
2

Язык: Swift

Последующие шаги как указано ниже:
// Объявляем

@IBOutlet weak var trTextDataRead: UITextView! 

// Cunstom метод

func insertTextView(text: String){ 
//Insert text 
trTextDataRead.text.append(text) 

//Scroll to the end 
let btm = NSMakeRange(trTextDataRead.text.lengthOfBytes(using: String.Encoding.utf8), 0) 
trTextDataRead.scrollRangeToVisible(btm) 
} 
0

Многие люди объясняют, как для прокрутки вниз, но одна вещь, которую следует отметить, что это не будет работать, если вы поместите его в viewDidLoad. Например: мне нужно было использовать это для прокрутки журнала до нижней части страницы при загрузке страницы. Для того, чтобы сделать это, я должен был осуществить следующий код

- (void) viewDidLoad { 
    [super viewDidLoad]; 
    [_logTextView setText:[Logger loadLogText]]; 
} 

- (void) viewDidLayoutSubviews { 
    [_logTextView 
    setContentOffset:CGPointMake(
          0.0, 
          _logTextView.contentSize.height 
         - _logTextView.frame.size.height 
        ) 
      animated:NO 
    ]; 
} 

Фактическая прокрутка UITextView не может быть сделано в viewDidLoad.

В моей реализации viewDidLoad я установил текст для текстового поля.

В моей реализации viewDidLayoutSubviews я установил смещение содержимого для UITextView, создав CGPoint, используя высоту содержимого текстовых просмотров минус высота самого текстового представления. Таким образом, когда он прокручивается донизу, нижняя часть текста находится не в верхней части окна, а внизу текст внизу находится в нижней части окна.

0

Swift 4

private func textViewScrollToBottom() { 
    let bottomRange = NSMakeRange(self.myTextView.text.count - 1, 1) 

    self.myTextView.scrollRangeToVisible(bottomRange) 
}