以编程方式滚动到textView的底部

时间:2015-10-30 00:33:16

标签: ios swift

我创建了一个向textView添加一些文本的按钮,我希望它在按下时自动滚动到底部,以便用户能够看到添加的新文本。 我无法在Swift中使用this解决方案,因为我不了解Objective-C。 有谁知道如何在Swift中滚动到textView的底部?感谢。

10 个答案:

答案 0 :(得分:18)

尝试内容偏移和scrolltoview解决方案,获得混合结果和不连贯的滚动;看了看下面似乎工作,并在需要时产生一致的滚动到底部。

在viewdidload中:

self.storyTextView.layoutManager.allowsNonContiguousLayout = false

然后在需要时:

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

答案 1 :(得分:12)

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提醒!

答案 2 :(得分:4)

因此,如果您点击发布的链接,则接受的答案会显示此目标-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中编写该方法定义?

接下来看一下该方法的主体。在Swift中if语句应该完全相同。 NSRange的创建几乎完全相同。你只需要稍微改变一下:

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

对于不了解Objective-C的人来说,最困难的部分是方法调用。它将消息scrollRangeToVisible发送到对象textView。传递的参数是bottom。看看你是否可以在Swift中重写该行。然后把整个东西放在一起。

答案 3 :(得分:4)

简单地说,myTextViewUITextView的问题:

let bottom = myTextView.contentSize.height

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

答案 4 :(得分:2)

语言:夫特

按照以下步骤操作:
    //声明

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

答案 5 :(得分:1)

我在添加了文字时自动滚动到底部的应用程序中使用以下内容:

首先,在初始化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 false 修复了contentSize问题。

添加 contentSize 观察器会观察textView的 contentSize 中的任何新变化,并调用 -observeValue(forKeyPath ...)进行更改时的功能。

-observeValue(...)函数中,我们首先得到底部(完全滚动到底部时为y contentOffset)。然后我们检查该值是否为负,这意味着contentSize高度小于textView框架高度,并且您无法真正进行任何滚动。如果你尝试以编程方式滚动该负值,它将导致许多人知道和喜爱的臭名昭着的抖动。因此,为了避免这种抖动,我们只需将值设置为已经应该的值, 0 ,或者您也可以返回

然后我们只测试 contentOffset 是否已经等于 bottom 值,我们给它新值。这样可以避免在不需要设置时设置 contentOffset

答案 6 :(得分:0)

UITextView有一个属性contentOffsent。您可以设置textView.contentOffsettextView.setContentOffset(offset, animated: true)

例如,如果文本视图的contentSize(100, 500)但文本视图的高度仅为100,则要滚动到底部,请将contentOffset属性设置为{ {1}}(这是一个垂直文本视图)。更一般地,滚动到底部的公式是(0, 400)。每按一次按钮,设置偏移量。

我还真的建议阅读文档并尝试弄明白。 Swift和iOS都有很好的文档记录,这样的问题很容易通过谷歌搜索到。

修改:这是有效的,因为textView.contentSize.height-textView.height继承自UITextView

旁注:我编写了一个UITextView子类,您可以在其中设置垂直文本对齐方式,因此如果将文本对齐方式设置为UIScrollView,则文本将与视图的底部对齐。

.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 } } 属性。我做了一些计算来确定偏移应该基于垂直对齐属性的位置,然后根据(通过滚动视图以编程方式滚动的方式设置内容偏移属性)

答案 7 :(得分:0)

如果您正在处理UITextView的attributedText属性:

在viewDidLoad()

self.storyTextView.layoutManager.allowsNonContiguousLayout = false
滚动方法中的

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

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

无法在viewDidLoad

中实际滚动UITextView

在我的viewDidLoad实现中,我设置了文本框的文本。

在我的viewDidLayoutSubviews实现中,我通过使用文本视图内容的高度减去文本视图本身的高度生成CGPoint来设置UITextView的内容偏移量。这样,当它滚动到底部时,文本的底部不在框的顶部,而是文本的底部位于框的底部。

答案 9 :(得分:0)

Swift 4

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

    self.myTextView.scrollRangeToVisible(bottomRange)
}