รับ UIScrollView เพื่อเลื่อนไปด้านบน


คำตอบ:


316

อัปเดตสำหรับ iOS 7

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

ORIGINAL

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

หรือถ้าคุณต้องการที่จะรักษาตำแหน่งเลื่อนแนวนอนและเพียงแค่รีเซ็ตตำแหน่งแนวตั้ง:

[self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, 0)
    animated:YES];

50
หากคุณกำลังทำเช่นนี้สำหรับ iOS 7 คุณอาจจะต้องคำนึงถึงความUIScrollView contentInsetโชคไม่ดี [self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, -self.scrollView.contentInset.top) animated:YES];ทำงานให้ฉันได้ไหม
runmad

11
ฉันสามารถเลื่อนไปด้านบนขวาใต้แถบนำทางและแถบสถานะ [scrollView setContentOffset:CGPointMake(0, -scrollView.contentInset.top) animated:YES];ใช้งานได้ใน iOS 6 และ 7
Amozoss

สิ่งนี้ไม่ได้ผลสำหรับฉันอาจเป็นเพราะฉันกำลังทำอะไรที่บ้าด้วยมุมมองแบบกลับหัวในชุดสไปรต์ แต่ถ้ามีคนอื่นบ้าเหมือนฉัน - และ scrollview ของคุณอยู่ที่ด้านล่างโดยค่าเริ่มต้น - มันจะเลื่อนไปด้านบน:[scrollView setContentOffset:CGPointMake(0, scrollView.contentSize.height-scrollView.frame.size.height) animated:YES];
GilesDMiddleton

ความคิดเห็นล่าสุด: คุณควรปรับเปลี่ยนสิ่งที่แทรกเนื้อหาโดยไม่คำนึงถึงเวอร์ชันของระบบปฏิบัติการ มีการใช้ iOS 7 เพื่อให้เนื้อหาเลื่อนด้านล่างแถบสถานะ แต่มันถูกเปิดเผยเป็นคุณสมบัติเสมอดังนั้นบางคนอาจถูกใช้งานเสมอ
ทอมมี่

2
สำหรับ iOS 11+ คำตอบของ Jakub Truhlářด้านล่างนี้โดยใช้ adjustContentInset มีประโยชน์อย่างน้อยในกรณีของฉัน
tnev

61

นี่คือส่วนขยาย Swift ที่ทำให้ง่าย:

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

การใช้งาน:

myScrollView.scrollToTop()

40

iOS 11 ขึ้นไป

adjustedContentInsetพยายามที่จะทำงานกับใหม่

ตัวอย่างเช่น (เลื่อนไปด้านบน):

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)

แม้ว่าคุณจะใช้prefersLargeTitles,safe areaฯลฯ




17

คำตอบสำหรับ Swift 2.0 / 3.0 / 4.0 และ iOS 7+:

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

8

ใน iOS7 ฉันมีปัญหาในการรับ scrollview ที่เฉพาะเจาะจงเพื่อไปด้านบนซึ่งทำงานใน iOS6 และใช้สิ่งนี้เพื่อตั้งค่า scrollview ให้ไปที่ด้านบน

[self.myScroller scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];

ฉันมีปัญหาเดียวกันใน iOS7 ไม่มีใครรู้วิธีเปิดใช้งานสิ่งนี้สำหรับ UITableView หรือไม่
DZenBot

1
มันตลกดีที่มันทำงานได้เมื่อภาพเคลื่อนไหวไม่ แต่ไม่ใช่ตอนที่ภาพเคลื่อนไหวเป็นใช่ ถ้าใช่แล้วมันจะเลื่อนไปจนถึง topdevgm16
Matt Becker


2

ในการทำซ้ำแถบสถานะ scrollToTop อย่างสมบูรณ์เราไม่เพียง แต่ต้องตั้งค่า contentOffset แต่ยังต้องการให้แน่ใจว่า scrollIndicators นั้นแสดงขึ้น มิฉะนั้นผู้ใช้สามารถหลงทางได้อย่างรวดเร็ว

flashScrollIndicatorsวิธีเดียวของประชาชนที่จะบรรลุนี้คือ น่าเสียดายที่การเรียกมันครั้งเดียวหลังจากตั้ง contentOffset จะไม่มีผลเพราะมันถูกรีเซ็ตทันที 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;
    });
}

ใน UIScrollViewDelegate ของคุณ (หรือ UITable / UICollectionViewDelegate) ใช้สิ่งนี้:

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

ความล่าช้าในการซ่อนนั้นสั้นกว่าเล็กน้อยเมื่อเปรียบเทียบกับแถบสถานะ scrollToTop แต่มันก็ยังดูดีอยู่

โปรดทราบว่าฉันใช้แท็กมุมมองเพื่อสื่อสารสถานะ "isScrollingToTop" ในทางที่ผิดเพราะฉันต้องการสิ่งนี้ในส่วนควบคุมมุมมอง หากคุณกำลังใช้แท็กสำหรับอย่างอื่นคุณอาจต้องการแทนที่ด้วย iVar หรือคุณสมบัติ


ฉันยังไม่ได้ทดสอบ แต่ควรโยนสิ่งนี้ใน runloop ถัดไปถ้าคุณใช้ DISPATCH_TIME_NOW แทน ขอบคุณสำหรับการทำงานนี้ไม่แน่ใจว่าฉันต้องการมัน แต่ยังดีที่จะรู้
Dan Rosenstark

ไม่นานมานี้และฉันจำไม่ได้ แต่ฉันเชื่อว่านี่ไม่ได้ผล การเลื่อนไปที่ runloop ถัดไปเป็นสิ่งแรกที่ฉันลองในกรณีเช่นนี้
Ortwin Gentz

2

ฉันคิดว่าฉันมีคำตอบที่ควรจะเข้ากันได้อย่างสมบูรณ์กับ iOS 11 เช่นเดียวกับรุ่นก่อนหน้า (สำหรับการเลื่อนแนวตั้ง)

สิ่งนี้คำนึงถึงการปรับปรุงใหม่ContentInsetและบัญชีสำหรับออฟเซ็ตเพิ่มเติมที่จำเป็นเมื่อprefersLargeTitlesเปิดใช้งานบนแถบนำทางซึ่งดูเหมือนจะต้องการออฟเซ็ต 52px เพิ่มเติมที่ด้านบนของสิ่งที่เป็นค่าเริ่มต้น

นี่เป็นเรื่องยากเล็กน้อยเพราะการเปลี่ยนแปลงที่ได้รับContContInsetขึ้นอยู่กับสถานะ titleBar (ชื่อเรื่องใหญ่ vs ชื่อเรื่องเล็ก ๆ ) ดังนั้นฉันต้องตรวจสอบและดูว่าความสูงของชื่อเรื่องบาร์คืออะไรและไม่ได้ใช้ออฟเซ็ต 52px ไม่พบวิธีอื่นในการตรวจสอบสถานะของแถบนำทางดังนั้นหากใครมีตัวเลือกที่ดีกว่าดูว่าความสูงเป็น> 44.0 ฉันอยากได้ยิน

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

แรงบันดาลใจจากโซลูชันของ Jakub


2

เป็นเรื่องปกติมากเมื่อแถบนำทางของคุณซ้อนทับส่วนเล็ก ๆ ของเนื้อหา scrollView และดูเหมือนว่าเนื้อหาจะไม่เริ่มจากด้านบน สำหรับการแก้ไขฉันทำ 2 สิ่ง:

  • ตัวตรวจสอบขนาด - มุมมองเลื่อน - ส่วนแทรกเนื้อหา -> เปลี่ยนจากอัตโนมัติเป็นไม่ใช้
  • Size Inspector - Constraints- "Align Top to" (Top Alignment Constraints) - รายการที่สอง -> เปลี่ยนจาก Superview.Top เป็น Safe AreaTopและค่า (เขตคงที่) ตั้งค่าเป็น 0

ส่วนแทรกเนื้อหา - ไม่เคย จัด ScrolView.Top ไปยัง Safe Area


1

เลื่อนไปที่ด้านบนสำหรับUITableViewController, UICollectionViewControllerหรือUIViewControllerมีUIScrollView

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


-4

ฉันลองทุกวิธี แต่ไม่มีอะไรทำงานให้ฉัน ในที่สุดฉันก็ทำเช่นนี้

ฉันเพิ่มself.view .addSubview(self.scroll)บรรทัดของรหัสใน viewDidLoad หลังจากเริ่มตั้งค่าเฟรมสำหรับมุมมองเลื่อนและเพิ่มส่วนประกอบในมุมมองเลื่อน

มันใช้งานได้สำหรับฉัน

ให้แน่ใจว่าคุณเพิ่ม self.view .addSubview(self.scroll)บรรทัดในการเริ่มต้น จากนั้นคุณสามารถเพิ่มองค์ประกอบ UI


โปรดลบสิ่งนี้ ในขณะที่มันสมเหตุสมผลในเวลานั้นปัญหาลำดับชั้นย่อยของคุณไม่เกี่ยวข้องกับคำถามนี้
Dan Rosenstark

1
@Cristik หากมุมมองการเลื่อนของคุณไม่อยู่ในลำดับชั้นการดูหรือคอมพิวเตอร์ของคุณปิดอยู่แน่นอนว่าสิ่งนี้จะไม่ทำงาน แต่ OP ถามบางสิ่งที่ค่อนข้างแคบ
Dan Rosenstark
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.