iOS 7 UIRefreshControl tintColor not working for beginRefreshing
IphoneObjective CXcodeUser InterfaceIos7Iphone Problem Overview
I'm trying to set a tintColor on my UIRefreshControl (building on iOS 7).
I enabled refreshing for the tableViewController in storyboard, then in my ViewController viewDidLoad
method i did the following:
[self.refreshControl setTintColor:[UIColor redColor]];
So now, when I pull to refresh, the color of the refresh control is red indeed:
I want my view to update automatically when it appears, so I did:
- (void)viewDidAppear:(BOOL)animated{
[self.refreshControl beginRefreshing];
}
It didn't show the spinning wheel, according to https://stackoverflow.com/a/16250679/1809736, I added
[self.tableView setContentOffset:CGPointMake(0, -self.refreshControl.frame.size.height) animated:NO];
to force show it. It shows it, but now it is back to default color:
If I try manually to pull to refresh afterwards, it is red.
I tried building it on iOS6 and it works as it should, so is that an iOS7 bug?
P.S.: it is not a problem with the simulator, I tried building it on device, same bug.
P.P.S: I built an example project, can you tell me if you have the same bug or if there is a problem in my code? Here is the link: http://d.pr/f/pGrV
Thanks a lot !
Iphone Solutions
Solution 1 - Iphone
Hey just stumbled into this exact issue.
Interestingly I fixed my code by setting the contentOffset first then calling beginRefreshing
if(self.tableView.contentOffset.y == 0){
self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
[self.refreshControl beginRefreshing];
}
You may want to animate this process:
[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];
}];
Hope this helps you.
W
Solution 2 - Iphone
SWIFT SOLUTION !
Insert the following code in the 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()
Solution 3 - Iphone
@william-george's answer set me in the right direction, but was giving me weird autolayout animation issues.
So here's the version that worked for me:
- (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
is the method tied to the UIRefreshControl
.
Solution 4 - Iphone
Add an extension for 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()
}
}
Solution 5 - Iphone
None of these answers are working for me correctly on iOS8, with the closest being @jpsim's answer but that still left an unsightly black refresh control during its fade-in animation (it would cross-fade between black and while over the course of the animation).
The solution that worked for me was to put this immediately after creating the refresh control in my 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];
Then to show the UIRefreshControl programmatically:
[self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y-self.refreshControlHeight) animated:YES];
[self.refreshControl beginRefreshing];
I had to store the height of the refresh control, as while it was set for the first invocation, subsequent calls would have a 0 height.
Solution 6 - Iphone
Solution for the tintColor issue: add this in viewDidLoad
[self.refreshControl setTintColor:[UIColor whiteColor]];
[self.refreshControl tintColorDidChange];
Now you have a white indicator when you call beginRefresh manually.
Solution 7 - Iphone
SWIFT:
I am using Swift and > iOS8. Most of the described workarounds didn't work for me. That's how I got it working:
In viewDidLoad:
customRefreshControl.tintColor = UIColor.clearColor()
The following doesn't have to be inside viewDidLoad. I put it in an extra function which get's called every time I update the tableView:
private func startRefreshControlAnimation() {
self.tableView.setContentOffset(CGPointMake(0, -self.customRefreshControl.frame.size.height), animated: true)
CATransaction.begin()
self.customRefreshControl.beginRefreshing()
CATransaction.commit()
}
Solution 8 - Iphone
I combined some of the previous answers. This works for me on iOS 9 and 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
})
}
Solution 9 - Iphone
I develop for iOS using Xamarin (C#) and came across the same issue.
I fixed the coloring issue, by setting the AttributedTitle
of the RefreshControl
:
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");
}
My Update method looks like this :
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;
}
}
Once the ViewDidAppear
, I call Update
programmatically.
Before setting the attributed title, my spinner would've been black.
Now it has the proper red color.
It's worth noticing, that this 'hack/fix' also comes with a second bug.
The first time you refresh, you'll notice that the AttributedTitle
is not displayed.
Refreshing a second (,third,fourth,...) time will display the title properly. But if you don't want a title, you just initialize it with an empty string, and this is not a big issue to you.
I hope this can be of use to others.
Solution 10 - Iphone
this hack is very working
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
}
}
}
Solution 11 - Iphone
I am working with Xamarin C# (iOS 10) and found that a combination of all of these answers is what fixed it for me.
In my ViewDidLoad
I have the following:
RefreshControl = new UIRefreshControl();
RefreshControl.TintColor = UIColor.White;
RefreshControl.ValueChanged += OnRefresh;
RefreshControl.BackgroundColor = UIColor.Clear;
And later I programmatically call the refresh animation in my ViewDidAppear
with the following:
BeginInvokeOnMainThread(() =>
{
UIView.Animate(0, 0.2, UIViewAnimationOptions.BeginFromCurrentState, () =>
{
TableView.SetContentOffset(new CGPoint(0, TableView.ContentOffset.Y - RefreshControl.Frame.Size.Height), true);
RefreshControl.AttributedTitle = new NSAttributedString("");
},
() =>
{
RefreshControl.BeginRefreshing();
});
});
Note the setting of the attributed title and animation block were the parts I was missing for my RefreshControl
to take my white tint color.
Thanks to all that have contributed to this question.
Solution 12 - Iphone
This is a bug which occurs when calling beginRefreshing()
on the refresh control right after setting its tintColor
property (or calling it from viewDidLoad()
(details [here][1]). There is an easy workaround however, by wrapping the beginRefreshing()
call inside a defer
statement (Swift 4):
override func viewDidLoad() {
super.viewDidLoad()
refreshControl.tintColor = .red
defer {
refreshControl.beginRefreshing()
}
}
[1]: https://github.com/davbeck/RefreshTintFail "here"
Solution 13 - Iphone
Set manually content offset for your tableView/scrollView before begin spinning:
tableView.setContentOffset(CGPoint(x: 0, y: tableView.contentOffset.y - (refreshControl.frame.size.height)), animated: true)
refreshControl.beginRefreshing()
......
Solution 14 - Iphone
Try setting the tintColor of your UIRefreshControl in viewWillAppear.
Solution 15 - Iphone
i found some Work Around i hope it works for you
[_TBL setContentOffset:CGPointMake(0,_TBL.contentOffset.y-_refreshControl.frame.size.height) animated:YES];
[_refreshControl performSelector:@selector(beginRefreshing) withObject:nil afterDelay:0.25];
[self getLatestUpdates];
Solution 16 - Iphone
I created a drop-in UIRefreshControl+beginRefreshing category that fixes this issue.
In brief, it fixes tintColor issue and manually tableView adjust contentOffset to make sure the refresh control is visible. Please try :)
Solution 17 - Iphone
When I set
tableView.refreshControl = refreshControl
several times where refreshControl is a different instance each time, I had the issue when refresh control color was always black and setting tint color to a different value didn't help.
So that I set tableView.refreshControl = refreshControl
only once and when I need to hide it I set alpha value, more details in this thread:
https://stackoverflow.com/questions/19480424/how-do-i-hide-a-uirefreshcontrol/54461766#54461766
Solution 18 - Iphone
Using UIView.animate
didn't work for me on Swift 4.
Here's what I ended up using
extension UIRefreshControl {
func beginRefreshingManually(with scrollView: UIScrollView, isFirstTime: Bool) {
if self.isRefreshing { return }
// Workaround: If we call setContentOffset on the first time that the screen loads
// we get a black refreshControl with the wrong size.
// We could just set the scrollView.contentOffset everytime, but it does not animate the scrolling.
// So for every other time, we call the setContentOffset animated.
if isFirstTime {
scrollView.contentOffset = CGPoint(x: 0, y: -self.frame.size.height)
} else {
scrollView.setContentOffset(CGPoint(x: 0, y: -self.frame.size.height), animated: true)
}
self.beginRefreshing()
}
}
Solution 19 - Iphone
Force the setTintColor to run in the main thread. (Main thread updates the ui).
[[NSOperationQueue mainQueue] addOperationWithBlock:^ {
[self.refreshControl setTintColor:[UIColor redColor]];
[self.refreshControl beginRefreshing];
}];