ios UIRefreshControl - 当 UITableViewController 在 UINavigationController 中时,beginRefreshing 不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14718850/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:09:43  来源:igfitidea点击:

UIRefreshControl - beginRefreshing not working when UITableViewController is inside UINavigationController

iosobjective-cuitableviewuinavigationcontrolleruirefreshcontrol

提问by wows

I've setup a UIRefreshControl in my UITableViewController (which is inside a UINavigationController) and it works as expected (i.e. pull down fires the correct event). However, if I programmatically invoke the beginRefreshinginstance method on the refresh control like:

我在我的 UITableViewController(它在 UINavigationController 内部)中设置了一个 UIRefreshControl,它按预期工作(即下拉触发正确的事件)。但是,如果我以编程方式调用beginRefreshing刷新控件上的实例方法,例如:

[self.refreshControl beginRefreshing];

Nothing happens. It should animate down and show the spinner. The endRefreshingmethod works properly when I call that after the refresh.

没发生什么事。它应该向下动画并显示微调器。endRefreshing当我在刷新后调用该方法时,该方法正常工作。

I whipped up a basic prototype project with this behavior and it works properly when my UITableViewController is added directly to application delegate's root view controller, e.g:

我用这种行为创建了一个基本的原型项目,当我的 UITableViewController 直接添加到应用程序委托的根视图控制器时,它可以正常工作,例如:

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

But if I add the tableViewControllerto a UINavigationController first, then add the navigation controller as the rootViewController, the beginRefreshingmethod no longer works. E.g.

但是,如果我tableViewController先将 加到 UINavigationController 中,然后将导航控制器添加为rootViewController,则该beginRefreshing方法不再有效。例如

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

My feeling is this has something to do with the nested view hierarchies within the navigation controller not playing nice with the refresher control - any suggestions?

我的感觉是这与导航控制器中的嵌套视图层次结构与刷新控件不兼容 - 有什么建议吗?

Thanks

谢谢

回答by Dmitry Shevchenko

It seems that if you start refreshing programmatically, you have to scroll the table view yourself, say, by changing contentoffset

似乎如果您开始以编程方式刷新,则必须自己滚动表视图,例如,通过更改 contentoffset

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

I would guess the reason for this is that it could be undesirable to scroll to the refresh control when user is in the middle/bottom of the table view?

我猜想这样做的原因是当用户位于表格视图的中间/底部时滚动到刷新控件可能是不可取的?

Swift 2.2 version by @muhasturk

@muhasturk 的 Swift 2.2 版本

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

In a nutshell, to keep this portable add this extension

简而言之,为了保持这种便携性,请添加此扩展

UIRefreshControl+ProgramaticallyBeginRefresh.swift

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

回答by Igotit

UITableViewController has automaticallyAdjustsScrollViewInsetsproperty after iOS 7. The table view may already have contentOffset, usually (0, -64).

UITableViewController在 iOS 7 之后有automaticAdjustsScrollViewInsets属性。table view 可能已经有 contentOffset,通常是 (0, -64)。

So the right way to show refreshControl after programmingly begin refreshing is adding refreshControl's height to existing contentOffset.

因此,在以编程方式开始刷新后显示 refreshControl 的正确方法是将 refreshControl 的高度添加到现有 contentOffset。

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

回答by Chris Wagner

Here's a Swift extension using the strategies described above.

这是使用上述策略的 Swift 扩展。

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

回答by Kyle Robson

None of the other answers worked for me. They would cause the spinner to show and spin, but the refresh action itself would never happen. This works:

其他答案都不适合我。它们会导致微调器显示和旋转,但刷新操作本身永远不会发生。这有效:

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

Note, this example uses a table view, but it could just as well have been a collection view.

注意,这个例子使用了一个表视图,但它也可以是一个集合视图。

回答by ancajic

The already mentioned approach:

已经提到的方法:

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

would make the spinner visible. But it wouldn't animate. The one thing I changed is the order of these two methods and everything worked:

将使微调器可见。但它不会动画。我改变的一件事是这两种方法的顺序,一切正常:

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

回答by Isaac Bosca

For Swift 4/4.1

对于 Swift 4/4.1

A mix of existing answer do the job for me:

现有答案的混合为我完成了这项工作:

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

Hope this helps!

希望这可以帮助!

回答by Ghulam Rasool

Here is Swift 3 and laterextension that shows spinner as well as animate it.

这是Swift 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()
      }
   }
}

回答by Peter Lapisu

See also this question

另见这个问题

UIRefreshControl not showing spiny when calling beginRefreshing and contentOffset is 0

UIRefreshControl 在调用 beginRefreshing 和 contentOffset 为 0 时不显示多刺

It looks like a bug to me, because it only occures when the contentOffset property of the tableView is 0

对我来说这看起来像是一个错误,因为它仅在 tableView 的 contentOffset 属性为 0 时发生

I fixed that with the following code (method for the UITableViewController) :

我使用以下代码(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){

        }];

    }
}

回答by Meilbn

It's works perfect to me:

它对我来说很完美:

Swift 3:

斯威夫特 3:

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

回答by LukasHromadnik

For Swift 5, for me the only thing missing was to call refreshControl.sendActions(.valueChanged). I made an extension to make it more cleaner.

对于 Swift 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)
    }

}