UIScrollView以编程方式滚动到底部

如何在代码中使UIScrollView滚动到底部?或者用更一般的方式,到子视图的任意点?

241441 次浏览

你可以使用UIScrollView的setContentOffset:animated:函数滚动到内容视图的任何部分。下面是一些滚动到底部的代码,假设你的scrollView是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中使用它时,对我不起作用。它滚动出边界,显示黑屏。

可选择的解决方案:

 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):

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];
}

使用(可选)footerViewcontentInset,解决方案是:

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。对于用户来说,这看起来很奇怪。

实现这个的代码是:

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];
}

只是对已有答案的一个改进。

CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset 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解决方案似乎对我来说是正确的,但你也需要考虑到集合视图嵌入,如果有一个已经设置。

修改后的代码为:

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并没有真正反映文本的实际大小,所以当试图滚动到底部时,它会有点偏离。确定实际内容大小的最佳方法实际上是使用NSLayoutManagerusedRectForTextContainer:方法:

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)

迅速:

   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)

如果contentSizebounds低怎么办?

对于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

滚动到表的最后一项的解决方案

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的接受答案,便于复制和粘贴

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开始,iPhone X引入了安全区域。这可能会影响scrollView的contentInset.

. 0

对于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)
}
}

引用:

如果你以某种方式改变了scrollView的contentSize(例如,在scrollView内部的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)
}

迅速:

你可以使用这样的扩展:

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