UIScrollView 以编程方式滚动到底部
Posted
技术标签:
【中文标题】UIScrollView 以编程方式滚动到底部【英文标题】:UIScrollView scroll to bottom programmatically 【发布时间】:2010-10-31 10:41:49 【问题描述】:如何让UIScrollView
在我的代码中滚动到底部?或者以更通用的方式,到子视图的任何一点?
【问题讨论】:
【参考方案1】:要滚动到底端,我们必须使用目标视图的最大高度。
import UIKit
extension UIScrollView
func scrollToBottomOf(targetView: UIView, animated: Bool)
setContentOffset(CGPoint(x:targetView.frame.minX, y:targetView.frame.maxY), animated: animated)
//func invocation example
optionScrollView.scrollToBottomOf(targetView: self.optionsStackView, animated: false)
【讨论】:
【参考方案2】:您可以使用 UIScrollView 的 setContentOffset:animated:
函数滚动到内容视图的任何部分。下面是一些滚动到底部的代码,假设你的 scrollView 是self.scrollView
:
目标-C:
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];
斯威夫特:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
希望有帮助!
【讨论】:
您可能希望将以下内容滚动到底部,而不是滚出滚动视图:CGPoint bottomOffset = CGPointMake(0, [self.scrollView contentSize].height - self.scrollView.frame.size .height); 您没有考虑插图。我认为您应该更喜欢这个底部偏移:CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
这在横向模式下不起作用!没有完全滚动到底部
如果contentSize
低于bounds
将无法正常工作。所以应该是这样的:scrollView.setContentOffset(CGPointMake(0, max(scrollView.contentSize.height - scrollView.bounds.size.height, 0) ), animated: true)
这处理底部插入,并超过 0:let bottomOffsetY = max(collectionView.contentSize.height - collectionView.bounds.height + collectionView.contentInset.bottom, 0)
【参考方案3】:
接受答案的 Swift 版本,便于复制粘贴:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height)
scrollView.setContentOffset(bottomOffset, animated: true)
【讨论】:
bottomOffset 在你的例子中应该是 let 而不是 var。 对,改了。 swift2的东西:) 你需要检查 scrollView.contentSize.height - scrollView.bounds.size.height > 0 否则你会得到奇怪的结果 当你有新的导航栏时,这个解决方案并不完美。 @Josh,还在等待 SO 发现这一点的那一天【参考方案4】:扩展 UIScrollView 以添加一个 scrollToBottom 方法:
extension UIScrollView
func scrollToBottom(animated:Bool)
let offset = self.contentSize.height - self.visibleSize.height
if offset > self.contentOffset.y
self.setContentOffset(CGPoint(x: 0, y: offset), animated: animated)
【讨论】:
这对现有答案有什么好处?【参考方案5】:斯威夫特:
你可以使用这样的扩展:
extension UIScrollView
func scrollsToBottom(animated: Bool)
let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height)
setContentOffset(bottomOffset, animated: animated)
用途:
scrollView.scrollsToBottom(animated: true)
【讨论】:
【参考方案6】:使用(可选)footerView
和 contentInset
,解决方案是:
CGPoint bottomOffset = CGPointMake(0, _tableView.contentSize.height - tableView.frame.size.height + _tableView.contentInset.bottom);
if (bottomOffset.y > 0) [_tableView setContentOffset: bottomOffset animated: YES];
【讨论】:
【参考方案7】:如果您以某种方式更改滚动视图 contentSize(例如,向滚动视图内的 stackView 添加一些内容),您必须在滚动之前调用 scrollView.layoutIfNeeded()
,否则它什么也不做。
例子:
scrollView.layoutIfNeeded()
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom)
if(bottomOffset.y > 0)
scrollView.setContentOffset(bottomOffset, animated: true)
【讨论】:
【参考方案8】:看起来这里的所有答案都没有考虑到安全区域。
从 ios 11 开始,iPhone X 引入了安全区域。这可能会影响滚动视图的contentInset
。
对于 iOS 11 及更高版本,正确滚动到底部并包含内容插图。您应该使用adjustedContentInset
而不是contentInset
。检查此代码:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.adjustedContentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
Objective-C
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.adjustedContentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];
Swift 扩展(保留原来的contentOffset.x
):
extension UIScrollView
func scrollsToBottom(animated: Bool)
let bottomOffset = CGPoint(x: contentOffset.x,
y: contentSize.height - bounds.height + adjustedContentInset.bottom)
setContentOffset(bottomOffset, animated: animated)
参考资料:
adjustedContentInset【讨论】:
【参考方案9】:对于水平滚动视图
如果你喜欢我有一个 Horizontal ScrollView 并且想要滚动到它的末尾(在我的例子中是它的最右边),你需要更改已接受答案的某些部分:
Objective-C
CGPoint rightOffset = CGPointMake(self.scrollView.contentSize.width - self.scrollView.bounds.size.width + self.scrollView.contentInset.right, 0 );
[self.scrollView setContentOffset:rightOffset animated:YES];
斯威夫特
let rightOffset: CGPoint = CGPoint(x: self.scrollView.contentSize.width - self.scrollView.bounds.size.width + self.scrollView.contentInset.right, y: 0)
self.scrollView.setContentOffset(rightOffset, animated: true)
【讨论】:
【参考方案10】:快速实现:
extension UIScrollView
func scrollToBottom(animated: Bool)
if self.contentSize.height < self.bounds.size.height return
let bottomOffset = CGPoint(x: 0, y: self.contentSize.height - self.bounds.size.height)
self.setContentOffset(bottomOffset, animated: animated)
使用它:
yourScrollview.scrollToBottom(animated: true)
【讨论】:
【参考方案11】:Xamarin.iOS 版本为UICollectionView
接受的答案,便于复制和粘贴
var bottomOffset = new CGPoint (0, CollectionView.ContentSize.Height - CollectionView.Frame.Size.Height + CollectionView.ContentInset.Bottom);
CollectionView.SetContentOffset (bottomOffset, false);
【讨论】:
【参考方案12】:Xamarin.iOS 接受答案的版本
var bottomOffset = new CGPoint (0,
scrollView.ContentSize.Height - scrollView.Frame.Size.Height
+ scrollView.ContentInset.Bottom);
scrollView.SetContentOffset (bottomOffset, false);
【讨论】:
【参考方案13】:滚动到表格视图的最后一项的解决方案:
斯威夫特 3:
if self.items.count > 0
self.tableView.scrollToRow(at: IndexPath.init(row: self.items.count - 1, section: 0), at: UITableViewScrollPosition.bottom, animated: true)
【讨论】:
【参考方案14】:考虑到contentInset
的 Swift 2.2 解决方案
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
这应该在扩展中
extension UIScrollView
func scrollToBottom()
let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height + contentInset.bottom)
setContentOffset(bottomOffset, animated: true)
请注意,您可能需要在滚动前检查bottomOffset.y > 0
【讨论】:
【参考方案15】:如果contentSize
低于bounds
怎么办?
对于 Swift 它是:
scrollView.setContentOffset(CGPointMake(0, max(scrollView.contentSize.height - scrollView.bounds.size.height, 0) ), animated: true)
【讨论】:
【参考方案16】:在 Swift 中使用 UIScrollView 的 setContentOffset:animated:
函数滚动到底部。
let bottomOffset : CGPoint = CGPointMake(0, scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
【讨论】:
【参考方案17】:迅速:
if self.mainScroll.contentSize.height > self.mainScroll.bounds.size.height
let bottomOffset = CGPointMake(0, self.mainScroll.contentSize.height - self.mainScroll.bounds.size.height);
self.mainScroll.setContentOffset(bottomOffset, animated: true)
【讨论】:
【参考方案18】:我发现contentSize
并不能真正反映文字的实际大小,所以在尝试滚动到底部时,它会有点偏离。确定实际内容大小的最佳方法实际上是使用NSLayoutManager
的usedRectForTextContainer:
方法:
UITextView *textView;
CGSize textSize = [textView.layoutManager usedRectForTextContainer:textView.textContainer].size;
要确定UITextView
中实际显示了多少文本,您可以通过从框架高度中减去文本容器插入来计算它。
UITextView *textView;
UIEdgeInsets textInsets = textView.textContainerInset;
CGFloat textViewHeight = textView.frame.size.height - textInsets.top - textInsets.bottom;
然后滚动就变得容易了:
// if you want scroll animation, use contentOffset
UITextView *textView;
textView.contentOffset = CGPointMake(textView.contentOffset.x, textSize - textViewHeight);
// if you don't want scroll animation
CGRect scrollBounds = textView.bounds;
scrollBounds.origin = CGPointMake(textView.contentOffset.x, textSize - textViewHeight);
textView.bounds = scrollBounds;
一些数字供参考,以了解不同大小代表空UITextView
。
textView.frame.size = (width=246, height=50)
textSize = (width=10, height=16.701999999999998)
textView.contentSize = (width=246, height=33)
textView.textContainerInset = (top=8, left=0, bottom=8, right=0)
【讨论】:
【参考方案19】:虽然Matt
解决方案对我来说似乎是正确的,但如果已经设置了集合视图插图,您还需要考虑集合视图插图。
修改后的代码将是:
CGSize csz = sv.contentSize;
CGSize bsz = sv.bounds.size;
NSInteger bottomInset = sv.contentInset.bottom;
if (sv.contentOffset.y + bsz.height + bottomInset > csz.height)
[sv setContentOffset:CGPointMake(sv.contentOffset.x,
csz.height - bsz.height + bottomInset)
animated:YES];
【讨论】:
【参考方案20】:最简单的解决方案:
[scrollview scrollRectToVisible:CGRectMake(scrollview.contentSize.width - 1,scrollview.contentSize.height - 1, 1, 1) animated:YES];
【讨论】:
谢谢。我忘了我将滚动视图更改为 UITableView 并且这段代码也适用于 UITableView,仅供参考。 为什么不只是:[scrollview scrollRectToVisible:CGRectMake(0, scrollview.contentSize.height, 1, 1) animated:YES];【参考方案21】:CGFloat yOffset = scrollView.contentOffset.y;
CGFloat height = scrollView.frame.size.height;
CGFloat contentHeight = scrollView.contentSize.height;
CGFloat distance = (contentHeight - height) - yOffset;
if(distance < 0)
return ;
CGPoint offset = scrollView.contentOffset;
offset.y += distance;
[scrollView setContentOffset:offset animated:YES];
【讨论】:
【参考方案22】:如果您不需要动画,这可行:
[self.scrollView setContentOffset:CGPointMake(0, CGFLOAT_MAX) animated:NO];
【讨论】:
【参考方案23】:只是对现有答案的增强。
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];
它还负责底部插图(以防您在键盘可见时使用它来调整滚动视图)
【讨论】:
这应该是正确的答案...而不是其他如果弹出键盘就会损坏的答案。【参考方案24】:确保内容底部可见的一个好方法是使用以下公式:
contentOffsetY = MIN(0, contentHeight - boundsHeight)
这可确保您的内容的底部边缘始终位于或高于视图的底部边缘。 MIN(0, ...)
是必需的,因为UITableView
(可能还有UIScrollView
)在用户尝试通过明显捕捉contentOffsetY = 0
进行滚动时确保contentOffsetY >= 0
。这对用户来说看起来很奇怪。
实现这个的代码是:
UIScrollView scrollView = ...;
CGSize contentSize = scrollView.contentSize;
CGSize boundsSize = scrollView.bounds.size;
if (contentSize.height > boundsSize.height)
CGPoint contentOffset = scrollView.contentOffset;
contentOffset.y = contentSize.height - boundsSize.height;
[scrollView setContentOffset:contentOffset animated:YES];
【讨论】:
【参考方案25】:救援类别!
将此添加到某处的共享实用程序标头中:
@interface UIScrollView (ScrollToBottom)
- (void)scrollToBottomAnimated:(BOOL)animated;
@end
然后到那个实用程序实现:
@implementation UIScrollView(ScrollToBottom)
- (void)scrollToBottomAnimated:(BOOL)animated
CGPoint bottomOffset = CGPointMake(0, self.contentSize.height - self.bounds.size.height);
[self setContentOffset:bottomOffset animated:animated];
@end
然后在任何你喜欢的地方实现它,例如:
[[myWebView scrollView] scrollToBottomAnimated:YES];
【讨论】:
总是,总是,总是,总是使用类别!完美:)【参考方案26】:滚动到顶部
- CGPoint topOffset = CGPointMake(0, 0);
- [scrollView setContentOffset:topOffset animated:YES];
滚动到底部
- CGPoint bottomOffset = CGPointMake(0, scrollView.contentSize.height - self.scrollView.bounds.size.height);
- [scrollView setContentOffset:bottomOffset animated:YES];
【讨论】:
【参考方案27】:在添加footerView
后,当我尝试在self.tableView
(iOS 4.1)
上的UITableViewController
中使用它时,对我不起作用。它滚动出边界,显示黑屏。
替代解决方案:
CGFloat height = self.tableView.contentSize.height;
[self.tableView setTableFooterView: myFooterView];
[self.tableView reloadData];
CGFloat delta = self.tableView.contentSize.height - height;
CGPoint offset = [self.tableView contentOffset];
offset.y += delta;
[self.tableView setContentOffset: offset animated: YES];
【讨论】:
【参考方案28】:将内容偏移设置为内容大小的高度是错误的:它会将内容的底部滚动到滚动视图的顶部,因此看不见。
正确的解决方法是将内容的底部滚动到滚动视图的底部,像这样(sv
是UIScrollView):
CGSize csz = sv.contentSize;
CGSize bsz = sv.bounds.size;
if (sv.contentOffset.y + bsz.height > csz.height)
[sv setContentOffset:CGPointMake(sv.contentOffset.x,
csz.height - bsz.height)
animated:YES];
【讨论】:
不应该是if (sv.contentOffset.y + csz.height > bsz.height)
吗?
@jeffamaphone - 感谢您的提问。实际上,在这一点上,我什至不确定该条件应该用于什么目的! setContentOffset:
命令很重要。
如果 setContentOffset 不执行任何操作,我认为它会避免调用?
@jeffamaphone - 过去,在设备旋转后,滚动视图的内容底部可能高于框架底部(因为如果我们旋转滚动视图,它的内容偏移量保持不变,但是由于自动调整大小,滚动视图高度可能已经增加)。条件是:如果发生这种情况,请将内容底部放回框架的底部。但是当我粘贴到代码中时包含条件是愚蠢的。但是,条件 is 正确地测试了它正在测试的内容。【参考方案29】:
valdyr,希望这对你有帮助:
CGPoint bottomOffset = CGPointMake(0, [textView contentSize].height - textView.frame.size.height);
if (bottomOffset.y > 0)
[textView setContentOffset: bottomOffset animated: YES];
【讨论】:
【参考方案30】:如果您使用 UITableview(它是 UIScrollView 的子类),我还发现了另一种有用的方法:
[(UITableView *)self.view scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
【讨论】:
仅供参考,这只是 UITableView 的功能以上是关于UIScrollView 以编程方式滚动到底部的主要内容,如果未能解决你的问题,请参考以下文章