UIScrollView gulir ke bawah secara terprogram


298

Bagaimana saya bisa membuat UIScrollViewgulir ke bagian bawah dalam kode saya? Atau dengan cara yang lebih umum, ke suatu titik subview?

Jawaban:


626

Anda dapat menggunakan fungsi UIScrollView setContentOffset:animated:untuk menggulir ke bagian mana pun dari tampilan konten. Berikut beberapa kode yang akan bergulir ke bawah, dengan anggapan scrollView Anda adalah 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];

Semoga itu bisa membantu!


25
Anda mungkin ingin yang berikut untuk menggulir ke bawah, bukannya keluar dari scrollview: CGPoint bottomOffset = CGPointMake (0, [self.scrollView contentSize] .height - self.scrollView.frame.size.height);
Grantland Chew

70
Anda tidak memperhitungkan inset. Saya pikir Anda sebaiknya memilih bottomOffset ini:CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
Martin

1
ini tidak berfungsi dalam mode Lansekap! tidak sepenuhnya gulir ke bawah
Mo Farhand

1
Tidak akan berfungsi dengan baik jika contentSizelebih rendah dari bounds. Jadi harus seperti ini:scrollView.setContentOffset(CGPointMake(0, max(scrollView.contentSize.height - scrollView.bounds.size.height, 0) ), animated: true)
Bartłomiej Semańczyk

1
Ini menangani inset bagian bawah, dan melampaui 0:let bottomOffsetY = max(collectionView.contentSize.height - collectionView.bounds.height + collectionView.contentInset.bottom, 0)
Senseful

136

Versi cepat dari jawaban yang diterima untuk menempelkan salinan dengan mudah:

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

3
bottomOffset harus dibiarkan dan tidak var dalam contoh Anda.
Hobbes the Tige

benar, mengubahnya. swift2 stuff :)
Esqarrouth

9
Anda perlu memeriksa apakah scrollView.contentSize.height - scrollView.bounds.size.height> 0 jika tidak, Anda akan mendapatkan hasil yang aneh
iluvatar_GR

2
Solusi ini tidak sempurna ketika Anda memiliki bilah navigasi baru.
Swift Rabbit

@Josh, Masih menunggu hari SO tahu tentang ini
Alexandre G

53

Solusi paling sederhana:

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

Terima kasih. Saya lupa saya mengubah scrollview saya menjadi UITableView dan kode ini juga berfungsi untuk UITableView, FYI.
LevinsonTeknologi

1
Mengapa tidak adil: [scrollview scrollRectToVisible: CGRectMake (0, scrollview.contentSize.height, 1, 1) animated: YES];
Johannes

29

Hanya penyempurnaan jawaban yang ada.

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

Ini menangani inset bagian bawah juga (jika Anda menggunakannya untuk menyesuaikan tampilan gulir saat keyboard terlihat)


Ini harus menjadi jawaban yang benar ... bukan yang lain yang akan pecah jika mereka memiliki keyboard yang muncul.
Ben Guild

20

Implementasi cepat:

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

Gunakan:

yourScrollview.scrollToBottom(animated: true)

19

Menyetel konten diimbangi dengan ketinggian ukuran konten salah: ia menggulung bagian bawah konten ke bagian atas tampilan gulir, dan karenanya tidak terlihat.

Solusi yang benar adalah dengan menggulir bagian bawah konten ke bagian bawah tampilan gulir, seperti ini ( svadalah 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
Bukankah seharusnya begitu if (sv.contentOffset.y + csz.height > bsz.height) {?
i_am_jorf

@jeffamaphone - Terima kasih telah bertanya. Sebenarnya pada titik ini saya bahkan tidak yakin apa tujuan dari kondisi yang seharusnya dilayani! Itu setContentOffset:perintah yang penting.
matt

Saya kira untuk menghindari panggilan setContentOffset jika tidak akan melakukan apa pun?
i_am_jorf

@jeffamaphone - Dulu setelah rotasi perangkat, tampilan gulir dapat berakhir dengan bagian bawah kontennya lebih tinggi dari bagian bawah bingkai (karena jika kita memutar tampilan gulir, kontennya offset tetap konstan, tetapi ketinggian tampilan gulir mungkin bertambah karena untuk autoresizing). Syaratnya mengatakan: Jika itu terjadi, letakkan kembali konten di bagian bawah bingkai. Tapi itu konyol saya untuk memasukkan kondisi ketika saya menempelkan dalam kode. Namun, kondisi ini menguji dengan benar untuk apa pengujian itu dilakukan.
matt

15

Solusi Swift 2.2, dengan contentInsetmempertimbangkan

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

Ini harus dalam ekstensi

extension UIScrollView {

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

Perhatikan bahwa Anda mungkin ingin memeriksa apakah bottomOffset.y > 0sebelum menggulir


14

Bagaimana jika contentSizelebih rendah daribounds ?

Untuk Swift adalah:

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

13

Gulir ke Atas

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

Gulir ke Bawah

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

7

Saya juga menemukan cara lain yang bermanfaat untuk melakukan ini jika Anda menggunakan UITableview (yang merupakan subkelas dari UIScrollView):

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

FYI, itu hanya kemampuan UITableView
OhadM

7

Menggunakan setContentOffset:animated:fungsi UIScrollView untuk menggulir ke bawah di Swift.

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

5

Sepertinya semua jawaban di sini tidak mempertimbangkan area aman. Sejak iOS 11, iPhone X telah memperkenalkan area yang aman. Ini mungkin memengaruhi scrollView contentInset.

Untuk iOS 11 dan di atasnya, untuk menggulir ke bawah dengan benar dengan memasukkan inset konten. Anda harus menggunakan adjustedContentInsetbukan contentInset. Periksa kode ini:

  • Cepat:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.adjustedContentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
  • Objektif-C
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.adjustedContentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];
  • Ekstensi cepat (ini menjaga yang asli 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)
    }
}

Referensi:


5

Dengan (opsional) footerViewdan contentInset, solusinya adalah:

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

4

Cepat:

Anda dapat menggunakan ekstensi seperti ini:

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

Menggunakan:

scrollView.scrollsToBottom(animated: true)

3

valdyr, harap ini akan membantu Anda:

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

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

2

Kategori untuk penyelamatan!

Tambahkan ini ke tajuk utilitas bersama di suatu tempat:

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

Dan kemudian untuk implementasi utilitas:

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

Kemudian Terapkan di mana pun Anda suka, misalnya:

[[myWebView scrollView] scrollToBottomAnimated:YES];

Selalu, selalu, selalu, selalu gunakan kategori! Sempurna :)
Fattie

2

Untuk ScrollView Horizontal

Jika Anda menyukai saya memiliki Horizontal ScrollView dan ingin menggulir ke akhir itu (dalam kasus saya di sebelah kanan itu), Anda perlu mengubah beberapa bagian dari jawaban yang diterima:

Objektif-C

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

Cepat

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

Jika Anda entah bagaimana mengubah scrollView contentSize (mis. Menambahkan sesuatu ke stackView yang ada di dalam scrollView) Anda harus memanggilscrollView.layoutIfNeeded() sebelum menggulir, jika tidak maka tidak akan melakukan apa-apa.

Contoh:

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

Cara yang baik untuk memastikan bagian bawah konten Anda terlihat adalah dengan menggunakan rumus:

contentOffsetY = MIN(0, contentHeight - boundsHeight)

Ini memastikan tepi bawah konten Anda selalu di atau di atas tepi bawah tampilan. Ini MIN(0, ...)diperlukan karena UITableView(dan mungkin UIScrollView) memastikan contentOffsetY >= 0ketika pengguna mencoba menggulir dengan menjentikkannya contentOffsetY = 0. Ini terlihat sangat aneh bagi pengguna.

Kode untuk mengimplementasikan ini adalah:

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

Jika Anda tidak membutuhkan animasi, ini berfungsi:

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

1

Sementara Mattsolusi tampaknya benar bagi saya, Anda perlu mempertimbangkan juga inset tampilan koleksi jika ada satu yang telah diatur.

Kode yang diadaptasi adalah:

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

Dengan cepat:

   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

Solusi untuk menggulir ke item terakhir dari tabel Lihat:

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

Tidak bekerja untuk saya, ketika saya mencoba untuk menggunakannya di UITableViewControlleratas self.tableView (iOS 4.1), setelah menambahkanfooterView . Itu bergulir keluar dari perbatasan, menunjukkan layar hitam.

Solusi alternatif:

 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

Saya menemukan bahwa contentSizeitu tidak benar-benar mencerminkan ukuran sebenarnya dari teks, jadi ketika mencoba untuk menggulir ke bawah, itu akan menjadi sedikit tidak aktif. Cara terbaik untuk menentukan ukuran konten sebenarnya adalah dengan menggunakan metode NSLayoutManager's usedRectForTextContainer::

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

Untuk menentukan berapa banyak teks yang benar-benar ditampilkan di UITextView, Anda dapat menghitungnya dengan mengurangi insets wadah teks dari ketinggian bingkai.

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

Maka menjadi mudah untuk menggulir:

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

Beberapa angka untuk referensi tentang apa ukuran yang berbeda mewakili untuk kosong 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

Perluas UIScrollView untuk menambahkan metode 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)
        }
    }
}

Apa yang ini tambahkan ke jawaban yang ada?
greybeard

-1

Versi Xamarin.iOS dari jawaban yang diterima

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

scrollView.SetContentOffset (bottomOffset, false);

-1

Versi Xamarin.iOS untuk UICollectionViewjawaban yang diterima untuk kemudahan dalam menyalin dan menempel

var bottomOffset = new CGPoint (0, CollectionView.ContentSize.Height - CollectionView.Frame.Size.Height + CollectionView.ContentInset.Bottom);          
CollectionView.SetContentOffset (bottomOffset, false);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.