如何在代码中使UIScrollView滚动到底部?或者用更一般的方式,到子视图的任意点?
UIScrollView
你可以使用UIScrollView的setContentOffset:animated:函数滚动到内容视图的任何部分。下面是一些滚动到底部的代码,假设你的scrollView是self.scrollView:
setContentOffset:animated:
self.scrollView
objective - 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)
希望有帮助!
我还发现了另一种有用的方法,在这种情况下,你正在使用UITableview(这是UIScrollView的子类):
[(UITableView *)self.view scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
在添加footerView后,当我试图在self.tableView (iOS 4.1)上的UITableViewController中使用它时,对我不起作用。它滚动出边界,显示黑屏。
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];
Valdyr,希望这对你有帮助
CGPoint bottomOffset = CGPointMake(0, [textView contentSize].height - textView.frame.size.height); if (bottomOffset.y > 0) [textView setContentOffset: bottomOffset animated: YES];
将内容偏移设置为内容大小的高度是错误的:它将内容的底部滚动到滚动视图的前,因此看不到。
正确的解决方案是滚动内容的底部到滚动视图的底,就像这样(sv是UIScrollView):
sv
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]; }
使用(可选)footerView和contentInset,解决方案是:
contentInset
CGPoint bottomOffset = CGPointMake(0, _tableView.contentSize.height - tableView.frame.size.height + _tableView.contentInset.bottom); if (bottomOffset.y > 0) [_tableView setContentOffset: bottomOffset animated: YES];
滚动到顶部
- 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];
类别来拯救!
将此添加到共享实用程序头的某处:
@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];
确保内容底部可见的一个好方法是使用以下公式:
contentOffsetY = MIN(0, contentHeight - boundsHeight)
这确保内容的下边缘始终位于视图的下边缘或高于视图的下边缘。MIN(0, ...)是必需的,因为当用户试图通过可见地捕捉contentOffsetY = 0来滚动时,UITableView(可能还有UIScrollView)确保contentOffsetY >= 0。对于用户来说,这看起来很奇怪。
MIN(0, ...)
contentOffsetY = 0
UITableView
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]; }
只是对已有答案的一个改进。
它还负责底部的嵌入(以防你在键盘可见时使用它来调整滚动视图)
如果你不需要动画,这是可行的:
[self.scrollView setContentOffset:CGPointMake(0, CGFLOAT_MAX) animated:NO];
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];
最简单的解决方案:
[scrollview scrollRectToVisible:CGRectMake(scrollview.contentSize.width - 1,scrollview.contentSize.height - 1, 1, 1) animated:YES];
虽然Matt解决方案似乎对我来说是正确的,但你也需要考虑到集合视图嵌入,如果有一个已经设置。
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]; }
Swift版本的易于复制粘贴的接受答案:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height) scrollView.setContentOffset(bottomOffset, animated: true)
我发现contentSize并没有真正反映文本的实际大小,所以当试图滚动到底部时,它会有点偏离。确定实际内容大小的最佳方法实际上是使用NSLayoutManager的usedRectForTextContainer:方法:
contentSize
NSLayoutManager
usedRectForTextContainer:
UITextView *textView; CGSize textSize = [textView.layoutManager usedRectForTextContainer:textView.textContainer].size;
要确定UITextView中实际显示了多少文本,可以通过从帧高度中减去文本容器嵌套来计算。
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)
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) }
使用UIScrollView的setContentOffset:animated:函数滚动到Swift的底部。
let bottomOffset : CGPoint = CGPointMake(0, scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom) scrollView.setContentOffset(bottomOffset, animated: true)
如果contentSize比bounds低怎么办?
bounds
对于Swift来说,它是:
scrollView.setContentOffset(CGPointMake(0, max(scrollView.contentSize.height - scrollView.bounds.size.height, 0) ), animated: true)
快速执行:
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)
一个Swift 2.2解决方案,考虑contentInset
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
bottomOffset.y > 0
滚动到表的最后一项的解决方案
Swift 3:
if self.items.count > 0 { self.tableView.scrollToRow(at: IndexPath.init(row: self.items.count - 1, section: 0), at: UITableViewScrollPosition.bottom, animated: true) }
Xamarin.iOS版本接受的答案
var bottomOffset = new CGPoint (0, scrollView.ContentSize.Height - scrollView.Frame.Size.Height + scrollView.ContentInset.Bottom); scrollView.SetContentOffset (bottomOffset, false);
Xamarin.iOS版本为UICollectionView的接受答案,便于复制和粘贴
UICollectionView
var bottomOffset = new CGPoint (0, CollectionView.ContentSize.Height - CollectionView.Frame.Size.Height + CollectionView.ContentInset.Bottom); CollectionView.SetContentOffset (bottomOffset, false);
用于水平ScrollView
如果你像我一样有一个水平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)
对于iOS 11及以上版本,正确地滚动到底部,包括插入的内容。你应该使用adjustedContentInset而不是contentInset。检查这段代码:
adjustedContentInset
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.adjustedContentInset.bottom) scrollView.setContentOffset(bottomOffset, animated: true)
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.adjustedContentInset.bottom); [self.scrollView setContentOffset:bottomOffset animated:YES];
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) } }
引用:
如果你以某种方式改变了scrollView的contentSize(例如,在scrollView内部的stackView中添加一些东西),你必须在滚动之前调用scrollView.layoutIfNeeded(),否则它什么都不做。
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) }
你可以使用这样的扩展:
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)
扩展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) } } }
要滚动到底部,我们必须使用目标视图的最大高度。
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)
正如这里所解释的 https://janeshswift.com/ios/swift/how-to-scroll-to-a-position-programmatically-in-uiscrollview/ < / p >
我们可以创建一个自定义UIScrollView扩展为
extension UIScrollView { func scrollToBottom() { let bottomOffset = CGPoint(x: 0, y: self.contentSize.height - self.bounds.height + self.contentInset.bottom) self.setContentOffset(bottomOffset, animated: true) } func scrollToTop() { let topOffset = CGPoint.zero self.setContentOffset(topOffset, animated: true) } func scrollToRightEnd(animated: Bool) { if self.contentSize.width < self.bounds.size.width { return } let rightOffset = CGPoint(x: self.contentSize.width - self.bounds.size.width, y: 0) self.setContentOffset(rightOffset, animated: animated) } func scrollToLeftEnd(animated: Bool) { if self.contentSize.width < self.bounds.size.width { return } let leftOffset = CGPoint.zero self.setContentOffset(leftOffset, animated: animated) } }
把它当作——
DispatchQueue.main.async { self.itemsScrollView.scrollToBottom() }