it-swarm.com.de

UIRefreshControl - beginRefreshing funktioniert nicht, wenn sich UITableViewController in UINavigationController befindet

Ich habe ein UIRefreshControl in meinem UITableViewController (der sich in einem UINavigationController befindet) eingerichtet und funktioniert wie erwartet (d. H. Pulldown löst das korrekte Ereignis aus). Wenn ich jedoch die Instanzmethode beginRefreshing für das Aktualisierungssteuerelement programmgesteuert aufrufe, wie folgt:

[self.refreshControl beginRefreshing];

Nichts passiert. Es sollte sich animieren und den Spinner zeigen. Die endRefreshing-Methode funktioniert ordnungsgemäß, wenn ich sie nach der Aktualisierung aufrufe.

Ich habe ein grundlegendes Prototypprojekt mit diesem Verhalten erstellt und es funktioniert ordnungsgemäß, wenn mein UITableViewController direkt zum Root-View-Controller des Anwendungsdelegaten hinzugefügt wird, z.

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

Wenn ich jedoch zuerst die Variable tableViewController einem UINavigationController hinzufüge und dann den Navigationscontroller als Variable rootViewController hinzufüge, funktioniert die Methode beginRefreshing nicht mehr. Z.B.

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

Meiner Meinung nach hat dies etwas damit zu tun, dass die verschachtelten Ansichtshierarchien innerhalb des Navigationscontrollers nicht mit der Auffrischungssteuerung Nice spielen - irgendwelche Vorschläge?

Vielen Dank 

105
wows

Es scheint, als müssten Sie, wenn Sie die Aktualisierung programmgesteuert starten, die Tabellenansicht selbst durchblättern, indem Sie beispielsweise contentoffset ändern

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

Ich denke, der Grund dafür ist, dass es unerwünscht sein kann, zu der Aktualisierungssteuerung zu scrollen, wenn sich der Benutzer in der Mitte/unter der Tabellenansicht befindet.

Swift 2.2 Version von @muhasturk

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

Um es kurz zu halten, fügen Sie diese Erweiterung hinzu

UIRefreshControl + ProgramicallyBeginRefresh.Swift

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

UITableViewController verfügt über automatischAdjustsScrollViewInsets -Eigenschaft nach iOS 7. Die Tabellenansicht hat möglicherweise bereits contentOffset, normalerweise (0, -64).

Daher ist der beste Weg, refreshControl anzuzeigen, nachdem die Aktualisierung programmiert wurde, das Hinzufügen der Höhe von refreshControl zu vorhandenem contentOffset.

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

Hier ist eine schnelle Erweiterung, die die oben beschriebenen Strategien verwendet.

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

Keine der anderen Antworten funktionierte für mich. Sie würden den Spinner dazu bringen, zu zeigen und zu drehen, aber die Auffrischungsaktion selbst würde niemals stattfinden. Das funktioniert:

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

Beachten Sie, dass in diesem Beispiel eine Tabellensicht verwendet wird, es könnte aber auch eine Sammlungsansicht sein.

12
Kyle Robson

Der bereits erwähnte Ansatz:

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

würde den Spinner sichtbar machen. Aber es würde nicht beleben. Das einzige, was ich geändert habe, ist die Reihenfolge dieser beiden Methoden und alles hat funktioniert:

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

Siehe auch diese Frage 

UIRefreshControl zeigt beim Aufruf von beginRefreshing keinen Stachel und contentOffset ist 0

Es sieht für mich wie ein Fehler aus, da er nur auftritt, wenn die contentOffset-Eigenschaft der tableView 0 ist

Ich habe das mit dem folgenden Code behoben (Methode für den 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){

        }];

    }
}
7
Peter Lapisu

Für Swift 4/4.1

Eine Mischung aus vorhandenen Antworten erledigen die Arbeit für mich:

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

Hoffe das hilft!

5
Isaac Bosca

Es funktioniert perfekt für mich:

Swift 3:

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

Hier ist die Swift 3-Erweiterung, die den Spinner zeigt und ihn animiert.

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()
      }
   }
}
4
Ghulam Rasool

Neben @Dymitry Shevchenko Lösung.

Ich habe Nizza Problemumgehung für dieses Problem gefunden. Sie können eine Erweiterung für UIRefreshControl erstellen, die die Methode überschreibt:

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

Sie können eine neue Klasse verwenden, indem Sie in Identity Inspector eine benutzerdefinierte Klasse für die Aktualisierungssteuerung im Interface Builder festlegen.

3
lyzkov

Fort Swift 2.2+

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

Wenn Sie Rxswift für Swift 3.1 verwenden, können Sie Folgendes verwenden:

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

Diese Arbeit für Swift 3.1, iOS 10.

3
jkyin

Für Swift 5 fehlte mir nur der Aufruf von refreshControl.sendActions(.valueChanged). Ich habe eine Erweiterung vorgenommen, um es sauberer zu machen.

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

}
0
LukasHromadnik

Ich verwende die gleiche Technik für das Sichtzeichen des Benutzers "data is update". Ein Ergebnis, das die Benutzer-App aus dem Hintergrund bringt, und Feeds/Listen werden mit der Benutzeroberfläche aktualisiert, so wie Benutzer Tabellen ziehen, um sich selbst zu aktualisieren. Meine Version enthält 3 Dinge

1) Wer sendet "Aufwachen"

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

2) Beobachter in UIViewController

- (void)viewDidLoad {
    [super viewDidLoad];

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

3) das Protokoll

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

 result

0
WINSergey