UIRefreshControl - UITableViewController UINavigationController के अंदर होने पर काम करना शुरू नहीं करना


120

मैंने अपने UITableViewController (जो एक UINavigationController के अंदर है) में एक UIRefreshControl सेटअप किया है और यह उम्मीद के मुताबिक काम करता है (यानी सही घटना को खींचता है)। हालाँकि, यदि मैं प्रोग्राम beginRefreshingकंट्रोल विधि को ताज़ा नियंत्रण पर लागू करता हूँ जैसे:

[self.refreshControl beginRefreshing];

कुछ नहीं हुआ। इसे नीचे चेतन करना चाहिए और स्पिनर को दिखाना चाहिए। endRefreshingविधि ठीक से काम करता है जब मैं ताज़ा करने के बाद कि कहते हैं।

मैंने इस व्यवहार के साथ एक मूल प्रोटोटाइप प्रोजेक्ट को व्हॉट्स अप किया और यह ठीक से काम करता है जब मेरे UITableViewController को सीधे डेलिगेट के रूट व्यू कंट्रोलर, जैसे:

self.viewController = tableViewController;
self.window.rootViewController = self.viewController;

लेकिन अगर मैं tableViewControllerपहले एक UINavigationController rootViewControllerकी beginRefreshingविधि जोड़ता हूं , तो नेविगेशन नियंत्रक को इस रूप में जोड़ें , विधि अब काम नहीं करती है। उदाहरण के लिए

UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:tableViewController];
self.viewController = navController;
self.window.rootViewController = self.viewController;

मेरी भावना यह है कि नेविगेशन नियंत्रक के भीतर नेस्टेड व्यू पदानुक्रम के साथ कुछ करना है जो रिफ्रेशर कंट्रोल के साथ अच्छा नहीं खेल रहा है - कोई सुझाव?

धन्यवाद

जवाबों:


195

ऐसा लगता है कि यदि आप प्रोग्रामेटिक रूप से रिफ्रेश करना शुरू करते हैं, तो आपको कंटेंटऑफसेट बदलकर, टेबल व्यू को खुद स्क्रॉल करना होगा

[self.tableView setContentOffset:CGPointMake(0, -self.refreshControl.frame.size.height) animated:YES];

मुझे लगता है कि इसका कारण यह होगा कि उपयोगकर्ता द्वारा टेबल व्यू के मध्य / तल में होने पर रिफ्रेश कंट्रोल को स्क्रॉल करना अवांछनीय हो सकता है?

स्विफ्ट 2.2 संस्करण @muhasturk द्वारा

self.tableView.setContentOffset(CGPoint(x: 0, y: -refreshControl.frame.size.height), animated: true)

संक्षेप में, इस पोर्टेबल को इस विस्तार को बनाए रखने के लिए

UIRefreshControl + ProgramaticallyBeginRefresh.swift

extension UIRefreshControl {
    func programaticallyBeginRefreshing(in tableView: UITableView) {
        beginRefreshing()
        let offsetPoint = CGPoint.init(x: 0, y: -frame.size.height)
        tableView.setContentOffset(offsetPoint, animated: true)        
    }
}

6
यह अजीब है, मेरे परीक्षणों में, एंडफ्रेशिंग आवश्यकतानुसार ऑफ़सेट समायोजित करता है
दिमित्री शेवचेंको

9
BTW, यदि आप ऑटो लेआउट का उपयोग कर रहे हैं, तो आप इस के साथ उत्तर में लाइन को बदल सकते हैं: [self.tableView setContentOffset: CGPointMake (0, -self.topLayoutGuide.length) एनिमेटेड: YES];
एरिक बेकर

4
@ EricBaker मुझे विश्वास है कि ऐसा नहीं होगा। सभी UITableViewControllers नेविगेशन बार नहीं दिखाते हैं। यह लंबाई 20 की एक topLoutoutGuide और एक ऑफसेट बहुत छोटा होता है।
फेबियो ओलिवेरा

3
@EricBaker आप उपयोग कर सकते हैं: [self.tableView setContentOffset: CGPointMake (0, self.topLayoutGuide.length -self.refreshControl.frame.size.height) एनिमेटेड: YES];
ZYiOS

1
कॉपी पेस्ट मेरे लिए काम करता है जो कमाल का है। मैं Apple के स्टोरीबोर्ड बिल्डर सामान से थक गया था।
ओकेसैबनी

78

UITableViewController में iOS 7. के बाद स्वचालित रूप से AdjustsScrollViewInsets संपत्ति है। तालिका दृश्य में पहले से ही सामग्री हो सकती है, आमतौर पर (0, -64)।

तो प्रोग्रामिंग को ताज़ा करने के बाद ताज़ा करने के लिए ताज़ा तरीका दिखाने के लिए सही तरीका मौजूदा सामग्री के लिए ताज़ा करेंकंट्रोल की ऊंचाई जोड़ रहा है।

 [self.refreshControl beginRefreshing];
 [self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControl.frame.size.height) animated:YES];

नमस्ते, बहुत बहुत धन्यवाद, मैं भी जादू बिंदु (0, -64) के बारे में उत्सुक हूं, जब मैं डिबगिंग के दौरान मिला था।
inix

2
@ स्थिति 20 के लिए स्थिति बार ऊंचाई + 44 नेविगेशन बार ऊंचाई के लिए
Igotit

1
इसके बजाय -64उपयोग करने के लिए बेहतर है-self.topLayoutGuide.length
डिओगो टी

33

यहां ऊपर वर्णित रणनीतियों का उपयोग करके एक स्विफ्ट एक्सटेंशन है।

extension UIRefreshControl {
    func beginRefreshingManually() {
        if let scrollView = superview as? UIScrollView {
            scrollView.setContentOffset(CGPoint(x: 0, y: scrollView.contentOffset.y - frame.height), animated: true)
        }
        beginRefreshing()
    }
}

UITableView के लिए काम करता है।
जुआन बोइरो

10
मैं sendActionsForControlEvents(UIControlEvents.ValueChanged)इस फ़ंक्शन के अंत में डालने की सलाह दूंगा, अन्यथा वास्तविक ताज़ा तर्क तर्क नहीं चलाया जाएगा।
कॉलिन बेसनेट

यह अब तक का सबसे सुंदर तरीका है। बेहतर कार्यक्षमता के लिए कॉलिन बेसनेट की टिप्पणी भी शामिल है। इसे एक बार परिभाषित करके पूरे प्रोजेक्ट में उपयोग किया जा सकता है!
जोगलिंड

1
@ColinBasnett: उस कोड को जोड़ना (जो अब sendActions है (के लिए: UIControlEvents.valueChanged)), एक अनंत लूप में परिणाम ...
केंडल हेल्मिस्सेटर गेलर

15

अन्य किसी भी उत्तर ने मेरे लिए काम नहीं किया। वे स्पिनर को दिखाने और स्पिन करने का कारण बनेंगे, लेकिन ताज़ा कार्रवाई कभी नहीं होगी। यह काम:

id target = self;
SEL selector = @selector(example);
// Assuming at some point prior to triggering the refresh, you call the following line:
[self.refreshControl addTarget:target action:selector forControlEvents:UIControlEventValueChanged];

// This line makes the spinner start spinning
[self.refreshControl beginRefreshing];
// This line makes the spinner visible by pushing the table view/collection view down
[self.tableView setContentOffset:CGPointMake(0, -1.0f * self.refreshControl.frame.size.height) animated:YES];
// This line is what actually triggers the refresh action/selector
[self.refreshControl sendActionsForControlEvents:UIControlEventValueChanged];

ध्यान दें, यह उदाहरण तालिका दृश्य का उपयोग करता है, लेकिन यह केवल संग्रह दृश्य हो सकता है।


इससे मेरी समस्या हल हो गई। लेकिन अब मैं उपयोग कर रहा हूं SVPullToRefresh, इसे प्रोग्रामेटिक रूप से कैसे खींचें?
Gank

1
@Gank मैंने कभी भी SVPullToRefresh का उपयोग नहीं किया है। क्या आपने उनके डॉक्स पढ़ने की कोशिश की है? डॉक्स के आधार पर यह काफी स्पष्ट प्रतीत होता है कि इसे प्रोग्रामेटिक रूप से नीचे खींचा जा सकता है: "यदि आप प्रोग्राम को रीफ्रेश करना चाहते हैं (उदाहरण के लिए व्यूडायपियर में :), तो आप ऐसा कर सकते हैं: [tableView triggerPullToRefresh];" देखें: github.com/samermette/ SVPullToRefresh
काइल रॉबसन

1
उत्तम! यह एनीमेशन के साथ मेरे लिए अजीब काम कर रहा था, लेकिन मैंने इसे बस बदल दियाscrollView.contentOffset = CGPoint(x: 0, y: scrollView.contentOffset.y - frame.height)
user1366265

13

पहले से ही वर्णित दृष्टिकोण:

[self.refreshControl beginRefreshing];
 [self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControl.frame.size.height) animated:YES];

स्पिनर को दिखाई देगा। लेकिन यह चेतन नहीं होगा। एक चीज जो मैंने बदली, वह है इन दो तरीकों का क्रम और सब कुछ काम किया:

[self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControl.frame.size.height) animated:YES];
[self.refreshControl beginRefreshing];

11

स्विफ्ट 4 / 4.1 के लिए

मौजूदा जवाब का एक मिश्रण मेरे लिए काम करते हैं:

refreshControl.beginRefreshing()
tableView.setContentOffset(CGPoint(x: 0, y: tableView.contentOffset.y - (refreshControl.frame.size.height)), animated: true)

उम्मीद है की यह मदद करेगा!


7

यह प्रश्न भी देखें

UIRefreshControl startRefreshing और contentOffset 0 पर कॉल करते समय रीढ़ नहीं दिखा रहा है

यह मेरे लिए एक बग की तरह दिखता है, क्योंकि यह केवल तब होता है जब टेबल व्यू की सामग्रीऑफसेट संपत्ति 0 होती है

मैंने तय किया कि निम्न कोड (UITableViewController के लिए विधि) के साथ:

- (void)beginRefreshingTableView {

    [self.refreshControl beginRefreshing];

    if (self.tableView.contentOffset.y == 0) {

        [UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){

            self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);

        } completion:^(BOOL finished){

        }];

    }
}

1
यह नहीं सच मैं दो अलग अलग UIViewControllers है जो दोनों के viewDidLoad पर 0 से contentOffset है और उनमें से एक सही ढंग से बुला [self.refreshControl beginRefreshing] और अन्य पर refreshControl नीचे खींचती है नहीं है,: /
simonthumper

दस्तावेज़ीकरण पर नियंत्रण प्रदर्शित करने के बारे में कुछ भी नहीं कहा गया है beginRefreshing, केवल यह कि इसकी स्थिति बदल जाती है। जैसा कि मैं देख रहा हूं, यह दो बार ताज़ा कार्रवाई शुरू करने से रोकने के लिए है, ताकि एक प्रोग्राम जिसे रिफ्रेश कहा जा सकता है, अभी भी चल रहा है, एक उपयोगकर्ता द्वारा शुरू की गई कार्रवाई दूसरे को शुरू नहीं करेगी।
कोएन।

मैंने setContentOffset: एनिमेटेड विधि का उपयोग करके समस्याओं का उल्लेख किया है, इसलिए इस समाधान ने मेरे लिए काम किया।
मार्क एचेवेरी

7

यहां स्विफ्ट 3 और बाद में एक्सटेंशन है जो स्पिनर के साथ-साथ इसे चेतन करता है।

import UIKit
extension UIRefreshControl {

func beginRefreshingWithAnimation() {

    DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {

        if let scrollView = self.superview as? UIScrollView {
            scrollView.setContentOffset(CGPoint(x: 0, y: scrollView.contentOffset.y - self.frame.height), animated: true)
          }
        self.beginRefreshing()
      }
   }
}

2
उपरोक्त सभी उत्तरों में से, यह एकमात्र ऐसा था जिसे मैं iOS 11.1 / xcode 9.1 पर काम कर सकता था
बसबस

1
asyncAfterवास्तव में स्पिनर एनीमेशन काम करता है क्या (10.2 आईओएस 12.3 / Xcode) है
francybiga

4

यह मेरे लिए एकदम सही है:

स्विफ्ट 3:

self.tableView.setContentOffset(CGPoint(x: 0, y: -self.refreshControl!.frame.size.height - self.topLayoutGuide.length), animated: true)

4

स्विफ्ट 5 के लिए, मेरे लिए केवल एक चीज गायब थी जिसे कॉल करना था refreshControl.sendActions(.valueChanged)। मैंने इसे और अधिक क्लीनर बनाने के लिए एक विस्तार किया।

extension UIRefreshControl {

    func beginRefreshingManually() {
        if let scrollView = superview as? UIScrollView {
            scrollView.setContentOffset(CGPoint(x: 0, y: scrollView.contentOffset.y - frame.height), animated: false)
        }
        beginRefreshing()
        sendActions(for: .valueChanged)
    }

}

3

@Dymitry Shevchenko समाधान के अलावा।

मुझे इस मुद्दे पर अच्छा समाधान मिला। आप UIRefreshControlउस अधिलेखित पद्धति का विस्तार कर सकते हैं :

// Adds code forgotten by Apple, that changes content offset of parent scroll view (table view).
- (void)beginRefreshing
{
    [super beginRefreshing];

    if ([self.superview isKindOfClass:[UIScrollView class]]) {
        UIScrollView *view = (UIScrollView *)self.superview;
        [view setContentOffset:CGPointMake(0, view.contentOffset.y - self.frame.size.height) animated:YES];
    }
}

आप इंटरफ़ेस बिल्डर में ताज़ा नियंत्रण के लिए पहचान निरीक्षक में कस्टम वर्ग निर्धारित करके नई कक्षा का उपयोग कर सकते हैं ।


3

फोर्ट स्विफ्ट 2.2+

    self.tableView.setContentOffset(CGPoint(x: 0, y: -refreshControl.frame.size.height), animated: true)

मैंने इसे स्वीकृत उत्तर के साथ मिला दिया है क्योंकि यह सिर्फ एक अद्यतन है।
ट्यूडर

3

यदि आप स्विफ्ट 3.1 के लिए Rxswift का उपयोग करते हैं, तो नीचे उपयोग कर सकते हैं:

func manualRefresh() {
    if let refreshControl = self.tableView.refreshControl {
        self.tableView.setContentOffset(CGPoint(x: 0, y: -refreshControl.height), animated: true)
        self.tableView.refreshControl?.beginRefreshing()
        self.tableView.refreshControl?.sendActions(for: .valueChanged)
    }
}

स्विफ्ट 3.1, आईओएस 10 के लिए यह काम करता है।


1
sendActionsट्रिगर करने के लिए इसका rxमतलब है कि RxSwiftकिसी को भी
उकसाने

मुझे TableViewController से रिफ्रेशकंट्रोल उदाहरण का उपयोग करना था, न कि टेबल व्यू। इसके अलावा, कि setContentOffset ने मेरे लिए iOS10 को लक्षित करने के लिए काम नहीं किया। यह एक काम करता है: self.tableView.setContentOffset(CGPoint(x:0, y:self.tableView.contentOffset.y - (refreshControl.frame.size.height)), animated: true)
nmdias

1

स्विफ्ट 5 पर परीक्षण किया गया

में इस का उपयोग करें viewDidLoad()

fileprivate func showRefreshLoader() {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
        self.tableView.setContentOffset(CGPoint(x: 0, y: self.tableView.contentOffset.y - (self.refreshControl.frame.size.height)), animated: true)
        self.refreshControl.beginRefreshing() 
    }
}

0

मैं शो उपयोगकर्ता के लिए एक ही तकनीक का उपयोग करता हूं "डेटा अपडेट है" विज़ुअल साइन। एक परिणाम उपयोगकर्ता पृष्ठभूमि से एप्लिकेशन लाता है और फीड / सूचियों को यूआई के साथ अपडेट किया जाएगा जैसे उपयोगकर्ता खुद को ताज़ा करने के लिए टेबल खींचते हैं। मेरे संस्करण में 3 चीजें हैं

1) जो "जाग" भेजते हैं

- (void)applicationDidBecomeActive:(UIApplication *)application {
    [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationHaveToResetAllPages object:nil];
}

2) UIViewController में पर्यवेक्षक

- (void)viewDidLoad {
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(forceUpdateData) name:kNotificationHaveToWakeUp:nil];
}

3) प्रोटोकॉल

#pragma mark - ForcedDataUpdateProtocol

- (void)forceUpdateData {
    self.tableView.contentOffset = CGPointZero;

    if (self.refreshControl) {
        [self.refreshControl beginRefreshing];
        [self.tableView setContentOffset:CGPointMake(0, -self.refreshControl.frame.size.height) animated:YES];
        [self.refreshControl performSelector:@selector(endRefreshing) withObject:nil afterDelay:1];
    }
}

परिणाम

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.