Cuộn UIScrollView xuống dưới cùng theo chương trình


298

Làm cách nào tôi có thể UIScrollViewcuộn xuống dưới cùng trong mã của mình? Hoặc theo một cách chung hơn, đến bất kỳ điểm nào của một cuộc phỏng vấn?

Câu trả lời:


626

Bạn có thể sử dụng setContentOffset:animated:chức năng của UIScrollView để cuộn đến bất kỳ phần nào của chế độ xem nội dung. Đây là một số mã sẽ cuộn xuống dưới cùng, giả sử scrollView của bạn là self.scrollView:

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

Mong rằng sẽ giúp!


25
bạn có thể muốn theo dõi dưới đây để cuộn xuống dưới cùng, thay vì ra khỏi scrollview: CGPoint bottom Offerset = CGPointMake (0, [self.scrollView contentSize] .height - self.scrollView.frame.size.height);
Grantland nhai

70
Bạn không tham gia vào tài khoản. Tôi nghĩ Bạn nên thích phần dưới cùng này:CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
Martin

1
Điều này không hoạt động trong chế độ Phong cảnh! không hoàn toàn cuộn xuống dưới cùng
Mo Farhand 10/08/2015

1
Nó sẽ không hoạt động đúng nếu contentSizethấp hơn bounds. Vì vậy, nó phải như thế này:scrollView.setContentOffset(CGPointMake(0, max(scrollView.contentSize.height - scrollView.bounds.size.height, 0) ), animated: true)
Bartłomiej Semańchot

1
Điều này xử lý phần dưới cùng và vượt quá 0:let bottomOffsetY = max(collectionView.contentSize.height - collectionView.bounds.height + collectionView.contentInset.bottom, 0)
Có ý thức vào

136

Phiên bản Swift của câu trả lời được chấp nhận để dán dễ dàng sao chép:

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

3
bottomPackset nên để và không var trong ví dụ của bạn.
Hobbes the Tige

đúng, đã thay đổi nó công cụ swift2 :)
Esqarrouth

9
bạn cần kiểm tra xem scrollView.contentSize.height - scrollView.bound.size.height> 0 nếu không bạn sẽ có kết quả wierd
iluvatar_GR

2
Giải pháp này không hoàn hảo khi bạn có thanh điều hướng mới.
Thỏ Swift

@Josh, Vẫn đang chờ ngày SO phát hiện ra điều này
Alexandre G

53

Giải pháp đơn giản nhất:

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

Cảm ơn. Tôi quên rằng tôi đã thay đổi cuộn xem của mình thành UITableView và mã này cũng hoạt động cho UITableView, FYI.
LevinsonTechnology

1
Tại sao không chỉ: [scrollview scrollRectToVisible: CGRectMake (0, scrollview.contentSize.height, 1, 1) hoạt hình: CÓ];
Julian

29

Chỉ là một sự nâng cao cho câu trả lời hiện có.

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

Nó cũng quan tâm đến phần dưới cùng (trong trường hợp bạn đang sử dụng phần đó để điều chỉnh chế độ xem cuộn của mình khi bàn phím hiển thị)


Đây phải là câu trả lời chính xác ... không phải là những câu khác sẽ bị hỏng nếu họ có bàn phím bật lên.
Ben Guild

20

Một triển khai thực hiện:

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

sử dụng nó:

yourScrollview.scrollToBottom(animated: true)

19

Đặt độ lệch nội dung theo chiều cao của kích thước nội dung là sai: nó cuộn phần dưới cùng của nội dung lên trên cùng của chế độ xem cuộn và do đó khuất tầm nhìn.

Giải pháp chính xác là cuộn phần dưới cùng của nội dung xuống dưới cùng của chế độ xem cuộn, như thế này ( svlà 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];
}

1
Có nên không if (sv.contentOffset.y + csz.height > bsz.height) {?
i_am_jorf

@jeffamaphone - Cảm ơn bạn đã hỏi thăm. Trên thực tế tại thời điểm này tôi thậm chí không chắc điều kiện nào được cho là phục vụ! Đó là setContentOffset:lệnh quan trọng.
matt

Tôi đoán nó sẽ tránh cuộc gọi setContent Offerset nếu nó không làm gì cả?
i_am_jorf

@jeffamaphone - Trước đây, sau khi xoay thiết bị, chế độ xem cuộn có thể kết thúc với đáy nội dung của nó cao hơn đáy khung (vì nếu chúng ta xoay chế độ xem cuộn thì phần bù nội dung của nó không đổi, nhưng chiều cao của chế độ xem cuộn có thể tăng lên để tự động hóa). Điều kiện cho biết: Nếu điều đó xảy ra, hãy đặt phần dưới của nội dung xuống dưới cùng của khung. Nhưng thật ngớ ngẩn khi tôi đưa vào điều kiện khi tôi dán mã. Điều kiện kiểm tra chính xác cho những gì nó đã được thử nghiệm, mặc dù.
matt

15

Một giải pháp Swift 2.2, có tính contentInsetđến

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

Điều này nên được mở rộng

extension UIScrollView {

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

Lưu ý rằng bạn có thể muốn kiểm tra nếu bottomOffset.y > 0trước khi cuộn


14

Nếu contentSizethấp hơn boundsthì sao?

Đối với Swift đó là:

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

13

Di chuyển lên đầu

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

Cuộn xuống dưới

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

7

Tôi cũng tìm thấy một cách hữu ích khác để làm điều này trong trường hợp bạn đang sử dụng UITableview (là một lớp con của UIScrollView):

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

FYI, đó chỉ là khả năng của UITableView
OhadM

7

Sử dụng setContentOffset:animated:chức năng của UIScrollView để cuộn xuống dưới cùng trong Swift.

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

5

Có vẻ như tất cả các câu trả lời ở đây đã không xem xét khu vực an toàn. Kể từ iOS 11, iPhone X đã có một khu vực an toàn được giới thiệu. Điều này có thể ảnh hưởng đến scrollView contentInset.

Đối với iOS 11 trở lên, để cuộn xuống phía dưới một cách chính xác với phần nội dung được bao gồm. Bạn nên sử dụng adjustedContentInsetthay vì contentInset. Kiểm tra mã này:

  • Nhanh:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.adjustedContentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
  • Mục tiêu-C
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.adjustedContentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];
  • Tiện ích mở rộng Swift (cái này giữ nguyên bản gốc 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)
    }
}

Người giới thiệu:


5

Với một (tùy chọn) footerViewcontentInset, giải pháp là:

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

4

Nhanh:

Bạn có thể sử dụng một tiện ích mở rộng như thế này:

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

Sử dụng:

scrollView.scrollsToBottom(animated: true)

3

valdyr, hy vọng điều này sẽ giúp bạn:

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

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

2

Thể loại để giải cứu!

Thêm phần này vào tiêu đề tiện ích được chia sẻ ở đâu đó:

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

Và sau đó để thực hiện tiện ích đó:

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

Sau đó, triển khai nó bất cứ nơi nào bạn muốn, ví dụ:

[[myWebView scrollView] scrollToBottomAnimated:YES];

Luôn luôn, luôn luôn, luôn luôn, luôn luôn sử dụng các thể loại! Hoàn hảo :)
Fattie

2

Đối với ScrollView ngang

Nếu bạn thích tôi có ScrollView ngang và muốn cuộn đến cuối của nó (trong trường hợp của tôi ở bên phải của nó), bạn cần thay đổi một số phần của câu trả lời được chấp nhận:

Mục tiêu-C

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

Nhanh

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)

2

Nếu bạn bằng cách nào đó thay đổi scrollView contentSize (ví dụ: thêm một cái gì đó vào stackView nằm trong scrollView), bạn phải gọi scrollView.layoutIfNeeded()trước khi cuộn, nếu không thì không có gì.

Thí dụ:

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

1

Một cách tốt để đảm bảo có thể nhìn thấy phần dưới của nội dung của bạn là sử dụng công thức:

contentOffsetY = MIN(0, contentHeight - boundsHeight)

Điều này đảm bảo cạnh dưới cùng của nội dung của bạn luôn ở hoặc trên cạnh dưới của chế độ xem. Điều MIN(0, ...)này là bắt buộc vì UITableView(và có lẽ UIScrollView) đảm bảo contentOffsetY >= 0khi người dùng cố gắng cuộn bằng cách chụp rõ ràng contentOffsetY = 0. Điều này có vẻ khá kỳ lạ với người dùng.

Mã để thực hiện điều này là:

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

1

Nếu bạn không cần hoạt hình, điều này hoạt động:

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

1

Mặc dù Mattgiải pháp có vẻ đúng với tôi, bạn cũng cần tính đến phần xem của bộ sưu tập nếu có một giải pháp đã được thiết lập.

Mã thích nghi sẽ là:

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

1

Trong nhanh chóng:

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

1

Giải pháp để cuộn đến mục cuối cùng của bảng Xem:

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

0

Không làm việc cho tôi, khi tôi cố gắng sử dụng nó trong UITableViewControllerngày self.tableView (iOS 4.1), sau khi thêm footerView. Nó cuộn ra khỏi viền, hiển thị màn hình đen.

Giải pháp thay thế:

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

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

0

Tôi thấy rằng contentSizenó không thực sự phản ánh kích thước thực tế của văn bản, vì vậy khi cố gắng cuộn xuống phía dưới, nó sẽ có một chút tắt. Cách tốt nhất để xác định kích thước nội dung thực tế là thực tế sử dụng NSLayoutManagercủa usedRectForTextContainer:phương pháp:

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

Để xác định số lượng văn bản thực sự được hiển thị trong UITextView, bạn có thể tính toán nó bằng cách trừ các phần chứa văn bản trong chiều cao khung.

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

Sau đó, nó trở nên dễ dàng để cuộn:

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

Một số số để tham khảo về những gì kích thước khác nhau đại diện cho một sản phẩm nào 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)

0

Mở rộng UIScrollView để thêm phương thức 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)
        }
    }
}

Điều này thêm gì vào câu trả lời hiện có?
greybeard

-1

Phiên bản Xamarin.iOS của câu trả lời được chấp nhận

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

scrollView.SetContentOffset (bottomOffset, false);

-1

Phiên bản Xamarin.iOS cho UICollectionViewcâu trả lời được chấp nhận để dễ dàng sao chép và dán

var bottomOffset = new CGPoint (0, CollectionView.ContentSize.Height - CollectionView.Frame.Size.Height + CollectionView.ContentInset.Bottom);          
CollectionView.SetContentOffset (bottomOffset, false);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.