iOS 7 UIRefreshControl的tintColor在beginRefreshing时无效

76

我想在我的UIRefreshControl上设置tintColor(基于iOS 7)。 我在storyboard中为tableViewController启用了刷新功能,然后在我的ViewController的viewDidLoad方法中进行了以下操作:

[self.refreshControl setTintColor:[UIColor redColor]];

现在,当我下拉刷新时,刷新控件的颜色确实是红色:

redSpiny

我希望我的视图在出现时能够自动更新,所以我做了以下操作:

- (void)viewDidAppear:(BOOL)animated{
    [self.refreshControl beginRefreshing];
}

根据https://dev59.com/p2Qo5IYBdhLWcg3wV-Qx#16250679所述,它没有显示旋转的圆圈,我进行了添加。

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

强制显示它。它会显示,但现在恢复为默认颜色:

输入图像描述

如果之后我手动尝试下拉刷新,它就变成了红色。

我尝试在iOS6上构建它,它按照应该的方式工作,那么这是一个iOS7的bug吗?

P.S.:这不是模拟器的问题,我在设备上构建了它,出现了相同的bug。

P.P.S: 我建立了一个示例项目,你能告诉我是否有相同的bug或者我的代码有问题吗?这是链接:http://d.pr/f/pGrV

非常感谢!


6
UIRefreshControl在iOS7下非常容易出现问题。我建议您使用开源产品,或者暂时忍受这些错误。请确保在 https://bugreport.apple.com 上提交错误报告。 - Léo Natan
5
他们似乎在 iOS7 中匆忙推出,UISearchViewController 也有一些问题。希望将来的更新能够修复这个问题。 - James
8
iOS 8 仍然存在这个 bug...很奇怪... - Macistador
2
还有iOS9。有人找到解决方案了吗? - oren
5
iOS 11也是一样的 :( - sudoExclaimationExclaimation
显示剩余5条评论
21个回答

54

嘿,我刚好遇到了这个问题。

有趣的是,我通过先设置 contentOffset,然后再调用 beginRefreshing 来修复了我的代码。

if(self.tableView.contentOffset.y == 0){
    self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
    [self.refreshControl beginRefreshing];
}

您可能希望对此过程进行动画处理:

[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
    self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
} completion:^(BOOL finished) {
    [self.refreshControl beginRefreshing];
}];
希望这能对你有所帮助。 W

有时候这并不起作用,因为偏移表的点是因为它有一些空间可以偏移,但只有在调用beginRefreshing之后...如果在此之前偏移它,它将没有太多可以偏移的! - newton_guima
2
按照广告所述正常工作。这很奇怪。谢谢 :) - Allan Spreys
1
在设置 contentOffset 后调用 "beginRefreshing" 非常重要!(至少在 ios8 上) - Macistador
1
我陷入困境了一段时间,但事实证明我正在使用[myTableView setContentOffset... animated:YES]。这对我没有起作用。直接设置偏移量并像上面那样使用UIView动画块。 - Rick Roberts
调用的顺序确实很重要。在代码文档中,这个奇怪的问题值得加上注释 "//???***"。 - SayeedHussain
显示剩余2条评论

28

SWIFT解决方案!在viewDidLoad中插入以下代码:

self.refreshControl.tintColor = UIColor.orangeColor()
self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height)
self.refreshControl.beginRefreshing()

Swift 3.1

self.refreshControl.tintColor = UIColor.orange
self.tableView.contentOffset = CGPoint(x:0, y:-self.refreshControl.frame.size.height)
self.refreshControl.beginRefreshing()

2
谢谢,这解决了我在viewDidLoad加载时遇到的一些问题。刷新控件的高度和颜色在第一次使用时都是错误的。 - Rob

8
@william-george的答案给了我正确的方向,但是在自动布局动画方面出现了问题。
这是适合我的版本:
- (void)programaticallyRefresh {
    // Hack necessary to keep UIRefreshControl's tintColor
    [self.scrollView setContentOffset:CGPointMake(0, -1.0f) animated:NO];
    [self.scrollView setContentOffset:CGPointMake(0, -self.refreshControl.frame.size.height) animated:YES];
    [self.refreshControl beginRefreshing];
    [self refresh];
}

-refresh 是与 UIRefreshControl 相关的方法。


7
添加一个UIResfreshControl的扩展。
extension UIRefreshControl {
    func beginRefreshingManually() {
        self.tintColor = UIColor.white
        if let scrollView = superview as? UIScrollView {
            scrollView.setContentOffset(CGPoint(x: 0, y:scrollView.contentOffset.y - frame.height), animated: false)
        }
        beginRefreshing()
    }
}

与其他解决方案相比,这个实现起来更好看且更有效。 :) 感谢Sefa和他的绝妙技巧。 - Bruno Reis Portela

4

对于iOS8,这些答案都不能正确地工作,最接近的是@jpsim的答案,但在淡入动画期间仍会留下不美观的黑色刷新控件(它会在动画过程中在黑色和白色之间交替淡入)。

对我有用的解决方案是,在我的viewDidLoad中创建刷新控件后立即添加以下代码:

self.refreshControl = [[UIRefreshControl alloc] init];
self.refreshControl.tintColor = [UIColor whiteColor];
...
self.refreshControlHeight = self.refreshControl.frame.size.height;
[self.tableView setContentOffset:CGPointMake(0, -1) animated:NO];
[self.tableView setContentOffset:CGPointMake(0, 0) animated:NO];

然后,要以编程方式显示UIRefreshControl:
[self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControlHeight) animated:YES];
[self.refreshControl beginRefreshing];

我不得不存储刷新控件的高度,因为第一次调用时已经设置了高度,但随后的调用会导致高度变为0。


1
谢谢,你能告诉我这只适用于-1的事实吗?我不喜欢神奇数字... - Rick van der Linde
这不是一个魔数,他只是将内容偏移量微不足道地改变,然后再改回来。 - Eran Goldin

3

SWIFT:

我正在使用Swift和> iOS8。大多数描述的解决方法对我没有用。这就是我让它工作的方式:

在viewDidLoad中:

customRefreshControl.tintColor = UIColor.clearColor()

以下代码不一定要放在viewDidLoad中。我将其放在了一个额外的函数中,该函数在每次更新tableView时被调用:
private func startRefreshControlAnimation() {

    self.tableView.setContentOffset(CGPointMake(0, -self.customRefreshControl.frame.size.height), animated: true)

    CATransaction.begin()
    self.customRefreshControl.beginRefreshing()
    CATransaction.commit()

}

3

我综合了之前的一些答案。这对我在iOS 9和Swift 2下有效:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    let contentOffset = self.tableView.contentOffset.y
    UIView.animateWithDuration(0, delay: 0, options: .BeginFromCurrentState, animations: {
        print(self.tableView.contentOffset.y)
            self.tableView.setContentOffset(CGPointMake(0, -self.refreshControl.frame.size.height), animated: false)
        }, completion: { finished in
            self.refreshControl.beginRefreshing()
            self.tableView.setContentOffset(CGPointMake(0, contentOffset/2-self.refreshControl.frame.size.height), animated: true)
            self.refresh() // Code that refresh table data
    })        
}

3

解决tintColor问题的方法:在viewDidLoad中添加以下代码

[self.refreshControl setTintColor:[UIColor whiteColor]];
[self.refreshControl tintColorDidChange];

现在,当您手动调用beginRefresh时,会出现白色指示器。


2
我使用Xamarin(C#)开发iOS应用程序时遇到了同样的问题。我通过设置RefreshControlAttributedTitle来解决了颜色问题:
private CGPoint originalOffset;
...
public override void ViewDidLoad ()
{
     base.ViewDidLoad ();
     ...
     originalOffset = TableView.ContentOffset; // Store the original offset of the table view
     RefreshControl = new UIRefreshControl (){ TintColor = UIColor.Red };
     RefreshControl.ValueChanged += ((s,e) => { Update (this, EventArgs.Empty); });
     // Hack so the TintColor of the RefreshControl will be properly set
     RefreshControl.AttributedTitle = new NSAttributedString ("Fetching data");
}

我的更新方法如下所示:
private async void Update(object sender, EventArgs args)
{
     try {
          TableView.UserInteractionEnabled = false;
          // I find -100 to be a big enough offset
          TableView.SetContentOffset (new CGPoint (0, -100), true);
          RefreshControl.BeginRefreshing ();
          ... // Fetch data & update table source 
          TableView.ReloadData ();
      } catch(Exception) {
          // Respond to exception
      } finally {
          // Put the offset back to the original
          TableView.SetContentOffset (originalOffset, true);
          RefreshControl.EndRefreshing ();
          TableView.UserInteractionEnabled = true;
      }
}

一旦 ViewDidAppear,我就通过编程调用Update。 在设置属性标题之前,我的旋转器是黑色的。 现在它有了正确的红色。
值得注意的是,这个“hack/fix”还带来了第二个bug。 第一次刷新时,您会注意到AttributedTitle没有显示。 第二次(第三次,第四次,...)刷新将正常显示标题。但是,如果您不想要标题,只需使用空字符串进行初始化即可,这对您来说并不是一个大问题。
希望这对其他人有所帮助。

1
这个黑客技巧非常有效。
var refreshWasProgramBeginning: Bool = false

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    if !refreshWasProgramBeginning {
        UIView.animate(withDuration: 0.25, animations: {
            self.tableView.contentOffset = CGPoint.init(x: 0, y: -self.refreshControl.frame.height)
        }) { (_) in
            self.refreshControl.beginRefreshing()
            self.refreshWasProgramBeginning = true
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接