我创建了一个向textView添加一些文本的按钮,我希望它在按下时自动滚动到底部,以便用户能够看到添加的新文本。 我无法在Swift中使用this解决方案,因为我不了解Objective-C。 有谁知道如何在Swift中滚动到textView的底部?感谢。
答案 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)
简单地说,myTextView
是UITextView
的问题:
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.contentOffset
或textView.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
。
在我的viewDidLoad
实现中,我设置了文本框的文本。
在我的viewDidLayoutSubviews
实现中,我通过使用文本视图内容的高度减去文本视图本身的高度生成CGPoint来设置UITextView的内容偏移量。这样,当它滚动到底部时,文本的底部不在框的顶部,而是文本的底部位于框的底部。
答案 9 :(得分:0)
Swift 4
private func textViewScrollToBottom() {
let bottomRange = NSMakeRange(self.myTextView.text.count - 1, 1)
self.myTextView.scrollRangeToVisible(bottomRange)
}