UIRefreshControl on UICollectionView only works if the collection fills the height of the container

IosUicollectionviewUirefreshcontrol

Ios Problem Overview


I'm trying to add a UIRefreshControl to a UICollectionView, but the problem is that the refresh control does not appear unless the collection view fills up the height of its parent container. In other words, unless the collection view is long enough to require scrolling, it cannot be pulled down to reveal the refresh control view. As soon as the collection exceeds the height of its parent container, it is pulled down and reveals the refresh view.

I have set up a quick iOS project with just a UICollectionView inside the main view, with an outlet to the collection view so that I can add the UIRefreshControlto it in viewDidLoad. There is also a prototype cell with the reuse identifier cCell

This is all the code in the controller, and it demonstrates the issue pretty well. In this code I set the height of the cell to 100, which isn't enough to fill the display, and therefore the view cannot be pulled and the refresh control won't show. Set it to something higher to fill the display, then it works. Any ideas?

@interface ViewController () <UICollectionViewDelegateFlowLayout, UICollectionViewDataSource>
@property (strong, nonatomic) IBOutlet UICollectionView *collectionView;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
	
	UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
	[self.collectionView addSubview:refreshControl];
}

-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
	return 1;
}

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
	return 1;
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
	return [collectionView dequeueReusableCellWithReuseIdentifier:@"cCell" forIndexPath:indexPath];
}

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
	return CGSizeMake(self.view.frame.size.width, 100);
}

Ios Solutions


Solution 1 - Ios

Try this:

self.collectionView.alwaysBounceVertical = YES;

Complete code for a UIRefreshControl

UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
refreshControl.tintColor = [UIColor grayColor];
[refreshControl addTarget:self action:@selector(refershControlAction) forControlEvents:UIControlEventValueChanged];
[self.collectionView addSubview:refreshControl];
self.collectionView.alwaysBounceVertical = YES;

Solution 2 - Ios

Attributes/Scroll View/Bounce Vertically in Storyboard/Xib

enter image description here

Solution 3 - Ios

Larry's answer in swift:

    let refreshControl = UIRefreshControl()
    refreshControl.tintColor = UIColor.blueColor()
    refreshControl.addTarget(self, action: "refresh", forControlEvents: .ValueChanged)
    collectionView.addSubview(refreshControl)
    collectionView.alwaysBounceVertical = true

Swift 3:

    let refreshControl = UIRefreshControl()
    refreshControl.tintColor = .blue
    refreshControl.addTarget(self, action: #selector(refresh), for: .valueChanged)
    collectionView.addSubview(refreshControl)
    collectionView.alwaysBounceVertical = true

Solution 4 - Ios

If your collectionview has a content size big enough to scroll vertically, it's OK, but in your case it's not.

You must enable the property AlwaysBounceVertical, so you could set self.collectionView.alwaysBounceVertical = YES;

Solution 5 - Ios

I too was facing the same issue, I was not able to use the UIRefreshControl until the UICollectionView's content size was large enough to scroll vertically,

Setting the bounces property of UICollectionView solved this

[self.collectionView setBounces:YES];
[self.collectionView setAlwaysBounceVertical:YES];

Solution 6 - Ios

I'm calling beginRefreshing() right after viewDidLoad(), but on some screens it doesn't work. And only collectionView.layoutIfNeeded() in viewDidLoad() helped me

Solution 7 - Ios

You must check in api call if collection view is in refreshing state then end refreshing to dismiss refreshing control.

private let refreshControl = UIRefreshControl()
 refreshControl.tintColor = .white
 refreshControl.addTarget(self, action: #selector(refreshData), for: .valueChanged)
 collectionView.addSubview(refreshControl)
 @objc func refreshData() {
    // API Call
 }
// Disable refresh control if already refreshing 
if refreshControl.isRefreshing {
    refreshControl.endRefreshing()
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMerottView Question on Stackoverflow
Solution 1 - IosLarryView Answer on Stackoverflow
Solution 2 - IosavdyushinView Answer on Stackoverflow
Solution 3 - IosAndrew SchreiberView Answer on Stackoverflow
Solution 4 - IosNghia LuongView Answer on Stackoverflow
Solution 5 - IosSaifView Answer on Stackoverflow
Solution 6 - IosNikolai IschukView Answer on Stackoverflow
Solution 7 - IosAsad JamilView Answer on Stackoverflow