Прокрутите вниз до конца текстового меню
Я сделал кнопку, которая добавляет некоторый текст в textView, и я хочу, чтобы она автоматически прокручивалась вниз, когда она была нажата, чтобы пользователь мог видеть добавленный новый текст.
Я не могу использовать это решение в Swift, потому что не знаю Objective-C. Кто-нибудь знает, как я могу прокручивать нижнюю часть текста в Swift? Благодарю.
Ответы
Ответ 1
Пробовал решения по смещению контента и scrolltoview, получал смешанные результаты и прерывистую прокрутку; оглядевшись вокруг ниже, казалось, работал, и при необходимости последовательная прокрутка вниз.
В viewdidload:
self.storyTextView.layoutManager.allowsNonContiguousLayout = false
Затем, когда это необходимо:
let stringLength:Int = self.storyTextView.text.characters.count
self.storyTextView.scrollRangeToVisible(NSMakeRange(stringLength-1, 0))
Ответ 2
Swift 4
let bottom = NSMakeRange(textLog.text.count - 1, 1)
textLog.scrollRangeToVisible(bottom)
Swift 3
let bottom = NSMakeRange(textLog.text.characters.count - 1, 1)
textLog.scrollRangeToVisible(bottom)
Обновление: спасибо @AntoineRucquoy для Swift 4 напоминания!
Ответ 3
Поэтому, если вы нажмете ссылку, которую вы опубликовали, принятый ответ показывает эту цель: 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. Затем соедините все это.
Ответ 4
Просто, где myTextView
- это UITextView
о UITextView
идет речь:
let bottom = myTextView.contentSize.height
myTextView.setContentOffset(CGPoint(x: 0, y: bottom), animated: true) // Scrolls to end
Ответ 5
Язык: Swift
Выполните следующие шаги:
// Объявляем
@IBOutlet weak var trTextDataRead: UITextView!
//Метод Кунстома
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)
}
Ответ 6
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
. Я делаю некоторые вычисления, чтобы выяснить, где смещение должно быть основано на свойстве вертикального выравнивания, а затем установить свойство смещения содержимого в соответствии с этим (как вы программно прокручиваете с просмотром прокрутки)
Ответ 7
Я использую следующее в приложении, которое автоматически прокручивается вниз при добавлении текста:
Сначала, когда вы инициализируете свой 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)
}
}
параметр allowNonContiguousLayout для ложных фиксированных проблем contentSize для меня.
Добавление наблюдателя contentSize будет наблюдать за любыми новыми изменениями в contentSize textView и вызовом функции -observeValue (forKeyPath...) при внесении изменений.
В функции -observeValue (...) мы сначала получаем дно (y contentOffset при полной прокрутке вниз). Затем мы проверяем, является ли это значение отрицательным, что означает, что высота contentSize меньше высоты кадра textView, и вы не можете действительно прокручивать. Если вы попытаетесь программно прокрутить это отрицательное значение, это вызовет этот печально известный джиттер, который многие знают и любят. Поэтому, чтобы избежать этого дрожания, мы просто устанавливаем значение того, что оно уже должно быть, 0, или вы также можете просто вернуться.
Затем мы просто проверяем, не удовлетворяет ли contentOffset нижним значением, мы даем ему это новое значение. Это позволяет избежать установки contentOffset, когда его не нужно устанавливать.
Ответ 8
Если вы имеете дело с атрибутом UITextView attributedText:
in viewDidLoad()
self.storyTextView.layoutManager.allowsNonContiguousLayout = false
в вашем методе прокрутки
let stringLength:Int = self.storyTextView.attributedText.string.characters.count
self.storyTextView.scrollRangeToVisible(NSMakeRange(stringLength-1, 0))
Ответ 9
Многие люди объясняют, как прокручивать дно, но нужно отметить, что это не сработает, если поместить его в 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, используя высоту содержимого текстовых просмотров минус высота самого текстового представления. Таким образом, когда он прокручивается донизу, нижняя часть текста находится не в верхней части окна, а внизу текст внизу находится в нижней части окна.
Ответ 10
Swift 4
private func textViewScrollToBottom() {
let bottomRange = NSMakeRange(self.myTextView.text.count - 1, 1)
self.myTextView.scrollRangeToVisible(bottomRange)
}