简体   繁体   English

UIScrollView 以编程方式滚动到底部

[英]UIScrollView scroll to bottom programmatically

How can I make a UIScrollView scroll to the bottom within my code?如何让UIScrollView在我的代码中滚动到底部? Or in a more generic way, to any point of a subview?或者以更通用的方式,到子视图的任何一点?

You can use the UIScrollView's setContentOffset:animated: function to scroll to any part of the content view.您可以使用 UIScrollView 的setContentOffset:animated:函数滚动到内容视图的任何部分。 Here's some code that would scroll to the bottom, assuming your scrollView is self.scrollView :下面是一些会滚动到底部的代码,假设您的 scrollView 是self.scrollView

Objective-C:目标-C:

CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];

Swift:迅速:

let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)

Hope that helps!希望有帮助!

Swift version of the accepted answer for easy copy pasting:已接受答案的 Swift 版本,便于复制粘贴:

let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height)
scrollView.setContentOffset(bottomOffset, animated: true)

最简单的解决方案:

[scrollview scrollRectToVisible:CGRectMake(scrollview.contentSize.width - 1,scrollview.contentSize.height - 1, 1, 1) animated:YES];

A swifty implementation:一个快速的实施:

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

use it:用它:

yourScrollview.scrollToBottom(animated: true)

Just an enhancement to the existing answer.只是对现有答案的增强。

CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];

It takes care of the bottom inset as well (in case you're using that to adjust your scroll view when the keyboard is visible)它也会处理底部的插图(以防您在键盘可见时使用它来调整滚动视图)

Setting the content offset to the height of the content size is wrong: it scrolls the bottom of the content to the top of the scroll view, and thus out of sight.将内容偏移设置为内容大小的高度是错误的:它将内容的底部滚动到滚动视图的顶部,从而看不见。

The correct solution is to scroll the bottom of the content to the bottom of the scroll view, like this ( sv is the UIScrollView):正确的解决方案是将内容的底部滚动到滚动视图的底部,如下所示( 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];
}

A Swift 2.2 solution, taking contentInset into account 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)

This should be in an extension这应该在扩展中

extension UIScrollView {

  func scrollToBottom() {
    let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height + contentInset.bottom)
    setContentOffset(bottomOffset, animated: true)
  }
}

Note that you may want to check if bottomOffset.y > 0 before scroll请注意,您可能需要在滚动前检查bottomOffset.y > 0

What if contentSize is lower than bounds ?如果contentSize低于bounds怎么办?

For Swift it is:对于 Swift,它是:

scrollView.setContentOffset(CGPointMake(0, max(scrollView.contentSize.height - scrollView.bounds.size.height, 0) ), animated: true)

Scroll To Top滚动到顶部

- CGPoint topOffset = CGPointMake(0, 0);
- [scrollView setContentOffset:topOffset animated:YES];

Scroll To Bottom滚动到底部

- CGPoint bottomOffset = CGPointMake(0, scrollView.contentSize.height - self.scrollView.bounds.size.height);
 - [scrollView setContentOffset:bottomOffset animated:YES];

Using UIScrollView's setContentOffset:animated: function to scroll to the bottom in Swift.使用 UIScrollView 的setContentOffset:animated:函数在 Swift 中滚动到底部。

let bottomOffset : CGPoint = CGPointMake(0, scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)

It looks like all of the answers here didn't take the safe area into consideration.看起来这里的所有答案都没有考虑安全区域。 Since iOS 11, iPhone X had a safe area introduced.从 iOS 11 开始,iPhone X 引入了安全区域。 This may affect the scrollView's contentInset .这可能会影响 scrollView 的contentInset

For iOS 11 and above, to properly scroll to the bottom with the content inset included.对于 iOS 11 及更高版本,正确滚动到包含内容插入的底部。 You should use adjustedContentInset instead of contentInset .您应该使用adjustedContentInset而不是contentInset Check this code:检查此代码:

  • Swift:迅速:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.adjustedContentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
  • Objective-C目标-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 extension (this keeps the original contentOffset.x ): 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)
    }
}

References:参考:

在您使用 UITableview(它是 UIScrollView 的子类)的情况下,我还发现了另一种有用的方法:

[(UITableView *)self.view scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

Swift:迅速:

You could use an extension like this:你可以使用这样的扩展:

extension UIScrollView {
    func scrollsToBottom(animated: Bool) {
        let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height)
        setContentOffset(bottomOffset, animated: animated)
    }
}

Use:用:

scrollView.scrollsToBottom(animated: true)

With an (optional) footerView and contentInset , the solution is:使用(可选) footerViewcontentInset ,解决方案是:

CGPoint bottomOffset = CGPointMake(0, _tableView.contentSize.height - tableView.frame.size.height + _tableView.contentInset.bottom);
if (bottomOffset.y > 0) [_tableView setContentOffset: bottomOffset animated: YES];

If you somehow change scrollView contentSize (ex. add something to stackView which is inside scrollView) you must call scrollView.layoutIfNeeded() before scrolling, otherwise it does nothing.如果您以某种方式更改了 scrollView contentSize (例如,向位于 scrollView 内的 stackView 添加一些内容),您必须在滚动前调用scrollView.layoutIfNeeded() ,否则它什么都不做。

Example:例子:

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

valdyr, hope this will help you: valdyr,希望这会帮助你:

CGPoint bottomOffset = CGPointMake(0, [textView contentSize].height - textView.frame.size.height);

if (bottomOffset.y > 0)
 [textView setContentOffset: bottomOffset animated: YES];

For Horizontal ScrollView对于水平滚动视图

If you like me has a Horizontal ScrollView and want to scroll to end of it (in my case to most right of it), you need to change some parts of the accepted answer:如果你喜欢我有一个 Horizo​​ntal ScrollView 并且想要滚动到它的末尾(在我的情况下是它的最右边),你需要更改已接受答案的某些部分:

Objective-C目标-C

CGPoint rightOffset = CGPointMake(self.scrollView.contentSize.width - self.scrollView.bounds.size.width + self.scrollView.contentInset.right, 0 );
[self.scrollView setContentOffset:rightOffset animated:YES];

Swift迅速

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)

Category to the rescue!类别来救援!

Add this to a shared utility header somewhere:将此添加到某处的共享实用程序标头中:

@interface UIScrollView (ScrollToBottom)
- (void)scrollToBottomAnimated:(BOOL)animated;
@end

And then to that utility implementation:然后到该实用程序实现:

@implementation UIScrollView(ScrollToBottom)
- (void)scrollToBottomAnimated:(BOOL)animated
{
     CGPoint bottomOffset = CGPointMake(0, self.contentSize.height - self.bounds.size.height);
     [self setContentOffset:bottomOffset animated:animated];
}
@end

Then Implement it wherever you like, for instance:然后在任何你喜欢的地方实现它,例如:

[[myWebView scrollView] scrollToBottomAnimated:YES];

A good way to ensure the bottom of your content is visible is to use the formula:确保内容底部可见的一个好方法是使用以下公式:

contentOffsetY = MIN(0, contentHeight - boundsHeight)

This ensures the bottom edge of your content is always at or above the bottom edge of the view.这可确保内容的底部边缘始终位于视图底部边缘或上方。 The MIN(0, ...) is required because UITableView (and probably UIScrollView ) ensures contentOffsetY >= 0 when the user tries to scroll by visibly snapping contentOffsetY = 0 . MIN(0, ...)是必需的,因为UITableView (可能还有UIScrollView )在用户尝试通过明显捕捉contentOffsetY = 0来滚动时确保contentOffsetY >= 0 contentOffsetY = 0 This looks pretty weird to the user.这对用户来说看起来很奇怪。

The code to implement this is:实现这一点的代码是:

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

While Matt solution seems correct to me you need to take in account also the collection view inset if there is one that has been set-up.虽然Matt解决方案对我来说似乎是正确的,但如果已经设置了集合视图,您还需要考虑集合视图插图。

The adapted code will be:改编后的代码将是:

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

In swift:迅速:

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

Solution to scroll to last item of a table View :滚动到表视图的最后一项的解决方案:

Swift 3 :斯威夫特3:

if self.items.count > 0 {
        self.tableView.scrollToRow(at:  IndexPath.init(row: self.items.count - 1, section: 0), at: UITableViewScrollPosition.bottom, animated: true)
}
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];

I found that contentSize doesn't really reflect the actual size of the text, so when trying to scroll to the bottom, it will be a little bit off.我发现contentSize并没有真正反映文本的实际大小,所以当试图滚动到底部时,它会有点偏离。 The best way to determine the actual content size is actually to use the NSLayoutManager 's usedRectForTextContainer: method:确定实际内容大小的最佳方法实际上是使用NSLayoutManagerusedRectForTextContainer:方法:

UITextView *textView;
CGSize textSize = [textView.layoutManager usedRectForTextContainer:textView.textContainer].size;

To determine how much text actually is shown in the UITextView , you can calculate it by subtracting the text container insets from the frame height.要确定UITextView实际显示的文本数量,您可以通过从框架高度中减去文本容器插入来计算它。

UITextView *textView;
UIEdgeInsets textInsets = textView.textContainerInset;
CGFloat textViewHeight = textView.frame.size.height - textInsets.top - textInsets.bottom;

Then it becomes easy to scroll:然后它变得容易滚动:

// 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;

Some numbers for reference on what the different sizes represent for an empty UITextView .一些数字用于参考不同大小代表空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)

Didn't work for me, when I tried to use it in UITableViewController on self.tableView (iOS 4.1) , after adding footerView .添加footerView后,当我尝试在self.tableView (iOS 4.1)上的UITableViewController使用它时,对我footerView It scrolls out of the borders, showing black screen.它滚动出边框,显示黑屏。

Alternative solution:替代解决方案:

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

Extend UIScrollView to add a scrollToBottom method:扩展 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)
        }
    }
}

To scroll to the bottom end, we have to work with the target view maximum height.要滚动到底部,我们必须使用目标视图的最大高度。

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)

As explained here https://janeshswift.com/ios/swift/how-to-scroll-to-a-position-programmatically-in-uiscrollview/如此处所述https://janeshswift.com/ios/swift/how-to-scroll-to-a-position-programmatically-in-uiscrollview/

We can create a custom UIScrollView extension as我们可以创建一个自定义的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)
    }
    
} 

Use It as --用作——

DispatchQueue.main.async {
    self.itemsScrollView.scrollToBottom()
}

Xamarin.iOS version for UICollectionView of the accepted answer for ease in copying and pasting接受答案的UICollectionViewXamarin.iOS版本,以便于复制和粘贴

var bottomOffset = new CGPoint (0, CollectionView.ContentSize.Height - CollectionView.Frame.Size.Height + CollectionView.ContentInset.Bottom);          
CollectionView.SetContentOffset (bottomOffset, false);

Xamarin.iOS version of accepted answer接受答案的Xamarin.iOS版本

var bottomOffset = new CGPoint (0,
     scrollView.ContentSize.Height - scrollView.Frame.Size.Height
     + scrollView.ContentInset.Bottom);

scrollView.SetContentOffset (bottomOffset, false);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM