UIScrollView scroll to bottom programmatically

IosObjective CSwiftUiscrollview

Ios Problem Overview


How can I make a UIScrollView scroll to the bottom within my code? Or in a more generic way, to any point of a subview?

Ios Solutions


Solution 1 - Ios

You can use the UIScrollView's setContentOffset:animated: function to scroll to any part of the content view. Here's some code that would scroll to the bottom, assuming your scrollView is 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];

Swift:

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

Hope that helps!

Solution 2 - Ios

Swift version of the accepted answer for easy copy pasting:

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

Solution 3 - Ios

Simplest Solution:

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

Solution 4 - Ios

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)

Solution 5 - Ios

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)

Solution 6 - Ios

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

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

Solution 7 - Ios

A Swift 2.2 solution, taking contentInset into account

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

Solution 8 - Ios

What if contentSize is lower than bounds?

For Swift it is:

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

Solution 9 - Ios

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

Solution 10 - Ios

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. This may affect the scrollView's contentInset.

For iOS 11 and above, to properly scroll to the bottom with the content inset included. You should use adjustedContentInset instead of 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
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):
extension UIScrollView {
    func scrollsToBottom(animated: Bool) {
        let bottomOffset = CGPoint(x: contentOffset.x,
                                   y: contentSize.height - bounds.height + adjustedContentInset.bottom)
        setContentOffset(bottomOffset, animated: animated)
    }
}

References:

Solution 11 - Ios

I also found another useful way of doing this in the case you are using a UITableview (which is a subclass of UIScrollView):

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

Solution 12 - Ios

Using UIScrollView's setContentOffset:animated: function to scroll to the bottom in Swift.

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

Solution 13 - Ios

With an (optional) footerView and contentInset, the solution is:

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

Solution 14 - Ios

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.

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

Solution 15 - Ios

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)

Solution 16 - Ios

valdyr, hope this will help you:

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

Solution 17 - Ios

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

Solution 18 - Ios

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:

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

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)

Solution 19 - Ios

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

Solution 20 - Ios

If you don't need animation, this works:

[self.scrollView setContentOffset:CGPointMake(0, CGFLOAT_MAX) animated:NO];

Solution 21 - Ios

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.

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

Solution 22 - Ios

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 23 - Ios

Solution to scroll to last item of a table View :

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

Solution 24 - Ios

Didn't work for me, when I tried to use it in UITableViewController on self.tableView (iOS 4.1), after adding 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];

Solution 25 - Ios

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

Solution 26 - Ios

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. The best way to determine the actual content size is actually to use the NSLayoutManager's usedRectForTextContainer: method:

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 *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.

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)

Solution 27 - Ios

Extend UIScrollView to add a scrollToBottom method:

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

Solution 28 - Ios

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)

Solution 29 - Ios

Xamarin.iOS version for UICollectionView of the accepted answer for ease in copying and pasting

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

Solution 30 - Ios

Xamarin.iOS version of accepted answer

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

scrollView.SetContentOffset (bottomOffset, false);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionnicoView Question on Stackoverflow
Solution 1 - IosBen GotowView Answer on Stackoverflow
Solution 2 - IosEsqarrouthView Answer on Stackoverflow
Solution 3 - IosHai HwView Answer on Stackoverflow
Solution 4 - IosduanView Answer on Stackoverflow
Solution 5 - Iosvivek241View Answer on Stackoverflow
Solution 6 - IosmattView Answer on Stackoverflow
Solution 7 - Iosonmyway133View Answer on Stackoverflow
Solution 8 - IosBartłomiej SemańczykView Answer on Stackoverflow
Solution 9 - IosTahir WaseemView Answer on Stackoverflow
Solution 10 - IosHonghao ZhangView Answer on Stackoverflow
Solution 11 - IosnicoView Answer on Stackoverflow
Solution 12 - IosKimView Answer on Stackoverflow
Solution 13 - IosPieterView Answer on Stackoverflow
Solution 14 - IosRobert KovalView Answer on Stackoverflow
Solution 15 - IosMauro GarcíaView Answer on Stackoverflow
Solution 16 - IosMishaView Answer on Stackoverflow
Solution 17 - IosBadPirateView Answer on Stackoverflow
Solution 18 - IosEsmaeilView Answer on Stackoverflow
Solution 19 - IosjjrscottView Answer on Stackoverflow
Solution 20 - IosKrys JurgowskiView Answer on Stackoverflow
Solution 21 - IostigueroView Answer on Stackoverflow
Solution 22 - IosPonjaView Answer on Stackoverflow
Solution 23 - IosMarionFlexView Answer on Stackoverflow
Solution 24 - IosvaldyrView Answer on Stackoverflow
Solution 25 - Ios8suhasView Answer on Stackoverflow
Solution 26 - IosmikehoView Answer on Stackoverflow
Solution 27 - Iosjeune-loupView Answer on Stackoverflow
Solution 28 - IosHabibView Answer on Stackoverflow
Solution 29 - IosAbdurView Answer on Stackoverflow
Solution 30 - IosAbdurView Answer on Stackoverflow