UIRefreshControl - 当UITableViewController在UINavigationController中时,beginRefreshing无效

wow*_*ows 114 objective-c uitableview uinavigationcontroller ios uirefreshcontrol

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

[self.refreshControl beginRefreshing];
Run Code Online (Sandbox Code Playgroud)

什么都没发生.它应该动画下来并显示微调器.endRefreshing刷新后调用时,该方法可以正常工作.

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

self.viewController = tableViewController;
self.window.rootViewController = self.viewController;
Run Code Online (Sandbox Code Playgroud)

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

UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:tableViewController];
self.viewController = navController;
self.window.rootViewController = self.viewController;
Run Code Online (Sandbox Code Playgroud)

我的感觉是这与导航控制器中的嵌套视图层次结构有关,不能与复习控件一起使用 - 任何建议?

谢谢

Dmi*_*nko 183

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

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

我猜这是因为当用户在表视图的中间/底部时滚动到刷新控件可能是不可取的?

@muhasturk的Swift 2.2版本

self.tableView.setContentOffset(CGPoint(x: 0, y: -refreshControl.frame.size.height), animated: true)
Run Code Online (Sandbox Code Playgroud)

简而言之,要保持此便携性,请添加此扩展程序

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)        
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,如果您使用自动布局,您可以用以下代码替换答案中的行:[self.tableView setContentOffset:CGPointMake(0,-self.topLayoutGuide.length)animated:YES]; (8认同)
  • 这很奇怪,在我的测试中,endRefreshing根据需要调整偏移量 (6认同)
  • @EricBaker我相信不会这样做.并非所有UITableViewControllers都显示导航栏.这将导致topLayoutGuide的长度为20,偏移量太小. (4认同)
  • 你可以使用@EricBaker:[self.tableView setContentOffset:CGPointMake(0,self.topLayoutGuide.length -self.refreshControl.frame.size.height)animated:YES]; (3认同)

Igo*_*tit 77

UITableViewController 在iOS 7之后具有automaticAdjustsScrollViewInsets属性.表视图可能已经有contentOffset,通常是(0,-64).

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

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

  • @inix 20表示状态栏高度+ 44表示导航栏高度 (2认同)
  • 使用“-self.topLayoutGuide.length”代替“-64”更好 (2认同)

Chr*_*ner 32

这是使用上述策略的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()
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我建议在这个函数的末尾放置`sendActionsForControlEvents(UIControlEvents.ValueChanged)`,否则不会运行实际的刷新逻辑逻辑. (10认同)

Kyl*_*son 13

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

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];
Run Code Online (Sandbox Code Playgroud)

请注意,此示例使用表视图,但它也可以是集合视图.

  • 完美的!不过,动画对我来说很奇怪,所以我只是将其替换为“scrollView.contentOffset = CGPoint(x: 0, y:scrollView.contentOffset.y -frame.height)” (2认同)

anc*_*jic 12

已经提到的方法:

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

会使微调器可见.但它不会动画.我改变的一件事是这两种方法的顺序和一切都有效:

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


Isa*_*sca 8

对于Swift 4/4.1

现有答案的混合为我做的工作:

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

希望这可以帮助!


Pet*_*isu 7

另见这个问题

调用beginRefreshing并且contentOffset为0时,UIRefreshControl没有显示多刺

它看起来像一个bug,因为它只在tableView的contentOffset属性为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){

        }];

    }
}
Run Code Online (Sandbox Code Playgroud)


Mei*_*lbn 5

它对我来说非常完美:

斯威夫特3:

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


Ghu*_*ool 5

这是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()
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

  • 在以上所有答案中,这是我可以在iOS 11.1 / xcode 9.1上使用的唯一答案 (2认同)

Luk*_*nik 5

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

}
Run Code Online (Sandbox Code Playgroud)