Dapatkan UIScrollView untuk menggulir ke atas

Jawaban:

316

PEMBARUAN UNTUK iOS 7

[self.scrollView setContentOffset:
    CGPointMake(0, -self.scrollView.contentInset.top) animated:YES];

ASLI

[self.scrollView setContentOffset:CGPointZero animated:YES];

atau jika Anda ingin mempertahankan posisi gulir horizontal dan cukup mengatur ulang posisi vertikal:

[self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, 0)
    animated:YES];
rob mayoff
sumber
50
Jika Anda melakukan ini untuk iOS 7, Anda mungkin harus mempertimbangkannya UIScrollView contentInset, sayangnya. [self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, -self.scrollView.contentInset.top) animated:YES];melakukan pekerjaan untuk saya
runmad
11
Saya dapat menggulir ke atas, tepat di bawah bilah navigasi dan status. [scrollView setContentOffset:CGPointMake(0, -scrollView.contentInset.top) animated:YES];Ini bekerja di iOS 6 & 7
Amozoss
Ini tidak berhasil untuk saya, mungkin karena saya melakukan sesuatu yang gila dengan tampilan terbalik dalam kit sprite. Tetapi jika ada orang lain yang sama gilanya dengan saya - dan scrollview Anda ada di bagian bawah secara default - ini akan menggulirnya ke atas:[scrollView setContentOffset:CGPointMake(0, scrollView.contentSize.height-scrollView.frame.size.height) animated:YES];
GilesDMiddleton
Komentar terlambat: Anda harus menyesuaikan untuk inset konten terlepas dari versi OS. iOS 7 kebetulan menggunakannya untuk memungkinkan konten gulir di bawah bilah status tetapi selalu terekspos sebagai properti, jadi selalu berpotensi digunakan oleh seseorang.
Tommy
2
Untuk iOS 11+, jawaban Jakub Truhlá below di bawah ini menggunakan customizedContentInset sangat membantu, setidaknya dalam kasus saya.
tnev
61

Berikut ini adalah ekstensi Swift yang membuatnya mudah:

extension UIScrollView {
    func scrollToTop() {
        let desiredOffset = CGPoint(x: 0, y: -contentInset.top)
        setContentOffset(desiredOffset, animated: true)
   }
}

Pemakaian:

myScrollView.scrollToTop()
Andrew Schreiber
sumber
40

iOS 11 ke atas

cobalah bekerja dengan yang baru adjustedContentInset.

Misalnya (gulir ke atas):

var offset = CGPoint(
    x: -scrollView.contentInset.left, 
    y: -scrollView.contentInset.top)

if #available(iOS 11.0, *) {
    offset = CGPoint(
        x: -scrollView.adjustedContentInset.left, 
        y: -scrollView.adjustedContentInset.top)    
}

scrollView.setContentOffset(offset, animated: true)

Bahkan jika Anda menggunakan prefersLargeTitles, safe areadll.

Jakub Truhlář
sumber
40

Untuk Swift 4

scrollView.setContentOffset(.zero, animated: true)
Rajasekhar Pasupuleti
sumber
23

Menggunakan setContentOffset:animated:

[scrollView setContentOffset:CGPointZero animated:YES];
Bryan Chen
sumber
17

Jawaban untuk Swift 2.0 / 3.0 / 4.0 dan iOS 7+:

let desiredOffset = CGPoint(x: 0, y: -self.scrollView.contentInset.top)
self.scrollView.setContentOffset(desiredOffset, animated: true)
layak
sumber
8

Di iOS7 saya kesulitan mendapatkan scrollview tertentu untuk pergi ke atas, yang berfungsi di iOS6, dan menggunakan ini untuk mengatur scrollview untuk pergi ke atas.

[self.myScroller scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
hoak
sumber
Saya memiliki masalah yang sama di iOS7. Adakah yang tahu cara mengaktifkan ini untuk UITableView?
DZenBot
1
Lucu bagaimana ini bekerja ketika animasi TIDAK, tetapi tidak ketika animasi adalah YA. Jika YA, maka itu bergulir hampir ke topdevgm16
Matt Becker
4

Jawaban rob mayoff versi Swift 3.0.1 :

self.scrollView.setContentOffset(
CGPoint(x: 0,y: -self.scrollView.contentInset.top),
animated: true)
Roni Leshes
sumber
2

Untuk sepenuhnya mereplikasi bilah status perilaku scrollToTop kita tidak hanya harus mengatur contentOffset tetapi juga ingin memastikan scrollindikator ditampilkan. Kalau tidak, pengguna dapat dengan cepat tersesat.

Satu-satunya metode publik untuk mencapai ini adalah flashScrollIndicators. Sayangnya, memanggilnya sekali setelah mengatur contentOffset tidak berpengaruh karena segera direset. Saya menemukan ini berfungsi ketika melakukan flash setiap kali masuk scrollViewDidScroll:.

// define arbitrary tag number in a global constants or in the .pch file
#define SCROLLVIEW_IS_SCROLLING_TO_TOP_TAG 19291

- (void)scrollContentToTop {
    [self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, -self.scrollView.contentInset.top) animated:YES];

    self.scrollView.tag = SCROLLVIEW_IS_SCROLLING_TO_TOP_TAG;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.scrollView.tag = 0;
    });
}

Dalam UIScrollViewDelegate Anda (atau UITable / UICollectionViewDelegate) terapkan ini:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.tag == SCROLLVIEW_IS_SCROLLING_TO_TOP_TAG) {
        [scrollView flashScrollIndicators];
    }
}

Sembunyikan penundaan agak lebih pendek dibandingkan dengan status bar perilaku scrollToTop tetapi masih terlihat bagus.

Perhatikan bahwa saya menyalahgunakan tag tampilan untuk mengomunikasikan keadaan "isScrollingToTop" karena saya memerlukan ini di seluruh pengontrol tampilan. Jika Anda menggunakan tag untuk hal lain, Anda mungkin ingin menggantinya dengan iVar atau properti.

Ortwin Gentz
sumber
Saya belum menguji, tetapi harus membuang ini pada runloop berikutnya jika Anda hanya menggunakan DISPATCH_TIME_NOW sebagai gantinya. Terima kasih telah melakukan pekerjaan ini, belum yakin saya membutuhkannya, tetapi senang mengetahuinya.
Dan Rosenstark
Beberapa saat yang lalu dan saya tidak ingat persis tetapi saya percaya ini tidak berhasil. Menunda runloop berikutnya biasanya adalah hal pertama yang saya coba dalam kasus tersebut.
Ortwin Gentz
2

Saya rasa saya punya jawaban yang harus sepenuhnya kompatibel dengan iOS 11 serta versi sebelumnya (untuk pengguliran vertikal)

Ini memperhitungkan baru adjustedContentInset dan juga menyumbang tambahan offset yang diperlukan bila prefersLargeTitles diaktifkan pada navigationbar yang tampaknya memerlukan 52px ekstra mengimbangi di atas apa pun defaultnya adalah

Ini sedikit rumit karena perubahan CustomizedContentInset tergantung pada status titleBar (judul besar vs judul kecil) jadi saya perlu memeriksa dan melihat apa ketinggian titleBar dan tidak menerapkan offset 52px jika sudah dalam keadaan besar. Tidak dapat menemukan metode lain untuk memeriksa keadaan navigasiBar jadi jika ada yang memiliki opsi yang lebih baik daripada melihat apakah tingginya> 44,0 Saya ingin mendengarnya

func scrollToTop(_ scrollView: UIScrollView, animated: Bool = true) {
    if #available(iOS 11.0, *) {
        let expandedBar = (navigationController?.navigationBar.frame.height ?? 64.0 > 44.0)
        let largeTitles = (navigationController?.navigationBar.prefersLargeTitles) ?? false
        let offset: CGFloat = (largeTitles && !expandedBar) ? 52: 0
        scrollView.setContentOffset(CGPoint(x: 0, y: -(scrollView.adjustedContentInset.top + offset)), animated: animated)
    } else {
        scrollView.setContentOffset(CGPoint(x: 0, y: -scrollView.contentInset.top), animated: animated)
    }
}

Terinspirasi oleh solusi Jakub

pengguna2898617
sumber
2

Ini sangat umum ketika bilah navigasi Anda tumpang tindih dengan sebagian kecil konten scrollView dan sepertinya konten dimulai bukan dari atas. Untuk memperbaikinya saya melakukan 2 hal:

  • Pemeriksa Ukuran - Tampilan Gulir - Insets Konten -> Ubah dari Otomatis menjadi Tidak Pernah.
  • Size Inspector - Constraints- "Align Top to" (Top Alignment Constraints) - Item kedua -> Ubah dari Superview.Top ke Safe Area.Top dan nilai (bidang konstan) ditetapkan ke 0

Isi konten - Tidak pernah Sejajarkan ScrolView.Top ke Safe Area.Top

Vitya Shurapov
sumber
1

Gulir ke atas untuk UITableViewController, UICollectionViewControlleratau yang UIViewControllermemilikiUIScrollView

extension UIViewController {

  func scrollToTop(animated: Bool) {
    if let tv = self as? UITableViewController {
        tv.tableView.setContentOffset(CGPoint.zero, animated: animated)
    } else if let cv = self as? UICollectionViewController{
        cv.collectionView?.setContentOffset(CGPoint.zero, animated: animated)
    } else {
        for v in view.subviews {
            if let sv = v as? UIScrollView {
                sv.setContentOffset(CGPoint.zero, animated: animated)
            }
        }
    }
  }
}
Shoaib
sumber
0

Di SWIFT 5 Cukup atur konten Offset ke nol

scrollView.setContentOffset(CGPoint.zero, animated: true)
Abdul Karim Khan
sumber
-4

Saya mencoba semua cara. Tetapi tidak ada yang berhasil untuk saya. Akhirnya saya suka ini.

Saya menambahkan self.view .addSubview(self.scroll)baris kode di viewDidLoad. Setelah mulai mengatur bingkai untuk tampilan gulir dan menambahkan komponen untuk tampilan gulir.

Ini berhasil untuk saya.

Pastikan Anda menambahkan self.view .addSubview(self.scroll)baris di awal. maka Anda dapat menambahkan elemen UI.

Narasimha Nallamsetty
sumber
Silakan hapus ini. Meskipun pada saat itu jelas masuk akal, masalah hierarki subview Anda tidak relevan dengan pertanyaan ini.
Dan Rosenstark
1
@ Kristik jika tampilan gulir Anda tidak ada dalam hierarki tampilan, atau komputer Anda dimatikan, tentu saja semua ini tidak akan berfungsi. Tetapi OP menanyakan sesuatu yang sangat sempit
Dan Rosenstark