In my application I use refresh control with collection view.
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds];
collectionView.alwaysBounceVertical = YES;
...
[self.view addSubview:collectionView];
UIRefreshControl *refreshControl = [UIRefreshControl new];
[collectionView addSubview:refreshControl];
iOS7 has some nasty bug that when you pull collection view down and don't release your finger when refreshing begins, vertical contentOffset shifts for 20-30 points down which results in ugly scroll jump.
Tables have this problem too if you use them with refresh control outside of UITableViewController. But for them it could be easily solved by assigning your UIRefreshControl instance to UITableView's private property called _refreshControl:
#interface UITableView ()
- (void)_setRefreshControl:(UIRefreshControl *)refreshControl;
#end
...
UITableView *tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self.view addSubview:tableView];
UIRefreshControl *refreshControl = [UIRefreshControl new];
[tableView addSubview:refreshControl];
[tableView _setRefreshControl:refreshControl];
But UICollectionView does not have such property so there must be some way to deal with it manually.
Having the same problem and found a workaround that seems to fix it.
This seems to be happening because the UIScrollView is slowing down the tracking of the pan gesture when you pull past the edge of the scrollview. However, UIScrollView is not accounting for changes to contentInset during tracking. UIRefreshControl changes contentInset when it activates, and this change is causing the jump.
Overriding setContentInset on your UICollectionView and accounting for this case seems to help:
- (void)setContentInset:(UIEdgeInsets)contentInset {
if (self.tracking) {
CGFloat diff = contentInset.top - self.contentInset.top;
CGPoint translation = [self.panGestureRecognizer translationInView:self];
translation.y -= diff * 3.0 / 2.0;
[self.panGestureRecognizer setTranslation:translation inView:self];
}
[super setContentInset:contentInset];
}
Interestingly, UITableView accounts for this by NOT slowing down tracking until you pull PAST the refresh control. However, I don't see a way that this behavior is exposed.
- (void)viewDidLoad
{
[super viewDidLoad];
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:#selector(scrollRefresh:) forControlEvents:UIControlEventValueChanged];
[self.collection insertSubview:self.refreshControl atIndex:0];
self.refreshControl.layer.zPosition = -1;
self.collection.alwaysBounceVertical = YES;
}
- (void)scrollRefresh:(UIRefreshControl *)refreshControl
{
self.refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:#"Refresh now"];
// ... update datasource
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:#"Updated %#", [NSDate date]]];
[self.refreshControl endRefreshing];
[self.collection reloadData];
});
}
Related
I am using UIRefreshControl in my table view. I have initiated refresh control in viewDidLoad:
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
self.refreshControl = refreshControl;
[self.bestDealsTableView addSubview:self.refreshControl];
I have a target method for scrolling:
-(void) handleRefresh:(UIRefreshControl *) refreshControl{
[self performSelector:#selector(updateDealsList) withObject:nil withObject:nil];
}
updateDealsList method:
- (void) updateDealsList {
self.dealsService = [[BestDealsService alloc] initServiceWithDelegate:self isLocalCall:NO];
[self.dealsService fetchBestDeals];
}
In my service response method:
[self.refreshControl endRefreshing];
self.isTableViewInRefreshMode = YES;
[self.bestDealsTableView reloadData];
Now, I have two issues:
1. My refresh Control is not hiding on success response from my service.
2. If I pull table view down, I can see a refresh control, but if I scroll down again, I see a new one below the previous one.
Image for first refresh control:
Here, after scrolling down again:
Note: I am using custom TableViewCell
This is how I fixed it:
// Pull To Refresh Code
if(self.refreshControl == nil){
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
self.refreshControl = refreshControl;
}
[self.myTableView addSubview:self.refreshControl];
Initialize your UIRefreshControl with:
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:#selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[self.bestDealsTableView addSubview:self.refreshControl];
and be sure to call [self.refreshControl endRefreshing];
tableView.contentOffset = CGPointMake(0, -100);
I have horizontal UICollectionView with UIRefreshControl:
self.refreshControlMain = [[UIRefreshControl alloc] init];
//self.refreshControlMain.tintColor = [UIColor grayColor];
[self.refreshControlMain addTarget:self action:#selector(refershControlAction) forControlEvents:UIControlEventValueChanged];
[self.collectionViewMain addSubview:self.refreshControlMain];
self.collectionViewMain.alwaysBounceVertical = YES;
self.collectionViewMain.pagingEnabled = YES;
self.collectionViewMain.showsHorizontalScrollIndicator = NO;
self.collectionViewMain.scrollEnabled = NO;
//Because user can't scroll horizontally (he needs to press next button)
But this code doesn't work, because I can't drag it vertically.
The only option I found is to set self.collectionViewMain.scrollEnabled = YES; (and in this case I can drag it vertically, so that refresh control appears), but in this case user is able to scroll horizontally (but user shouldn't be able to do that).
Is there any option to use refresh control in my situation?
update:
I don't need horisontal refresh control. I have horisontal collectionview, but I need vertical refresh control. if I put "self.collectionViewMain.scrollEnabled = YES" in my code, it works. but I need user not be able to scroll himself.
UIRefreshControl does not support horizontal use natively.
There are various solutions whereby it has been extended for horizontal use.
Check out this link.
Or as per this answer you could use a UITableViewController that is rotated 90 degrees.
Add [self.view setTransform:CGAffineTransformMakeRotation(-M_PI / 2)]; in the UITableViewController class during setup.
Example using UITableView (and not UITableViewController):
table_ = [[UITableView alloc] initWithFrame:self.bounds];
[table_ setDelegate:self];
[table_ setDataSource:self];
[table_ registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
[table_ setTransform:CGAffineTransformMakeRotation(-M_PI / 2)];
UIRefreshControl *ctrl = [[UIRefreshControl alloc] init];
[ctrl setBackgroundColor:[UIColor yellowColor]];
[table_ addSubview:ctrl];
[self addSubview:table_];
Make sure to remember to rotate the content back again in the opposite direction!
I want to implement Pull To Refresh to my UITableViewController by using UIRefreshControl. Here what i tried so far.
- (void)viewDidLoad
{
.....
////********* Pull to refresh ************/
UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
refresh.attributedTitle = [[NSAttributedString alloc] initWithString:#"Pull to Refresh"];
refresh.tintColor = [UIColor magentaColor];
// [self.tableView addSubview:refresh];
// [self.refreshControl setEnabled:YES];
[refresh addTarget:self action:#selector(pullToRefresh:) forControlEvents:UIControlEventValueChanged];
self.refreshControl = refresh;
}
-(void)pullToRefresh:(UIRefreshControl *)refresh {
[refresh beginRefreshing];
refresh.attributedTitle = [[NSAttributedString alloc] initWithString:#"Refreshing.."];
[self loadRecentActivities];
}
But when i pull the tableview neither activity indicator nor title is visible, however pullToRefresh is called and table refreshed.My app supports iOS7.0+.
What i'm missing? Any help would be appreciated?
Edit: I'v tried with [self.refreshControl setEnabled:YES]; and [self.refreshControl setEnabled:YES]; as mentioned in my edited code, but still no luck.
This is how my tableview looks like when i pull it to refresh-
Final Solution: For table view background i was using
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background.png"]];
self.tableView.backgroundView = imageView;
Refresh indicator and title was hidden behind the self.tableView.backgroundView instead use
[self.tableView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"background.png"]]];
and it solves my problem. also many thanks to Balram Tiwari please see his answer if you still have problem.
Just add self.tableView.backgroundView.layer.zPosition -= 1; under the initialisation code for refreshControl.
Actually you have your refresh controller there in the tableView, but it is behind the navigationBar. (Sounds different, right), Here is the catch,
When you are using code in iOS7, by default the UIViewController takes the (edgesForExtendedLayout) whole screen. That means your (0,0) will start from the top left corner, underneath the navigationBar.
So your tableView is actually starting from there. So to get rid of it, you just specify the edgesForExtendedLayout for your viewController in your viewDidLoad Method.
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
After that it should be visible.
Before above Fix:
After the Fix.
hope that helps.
I would like to show activityindicator and load more content from server when scroll goes out of UITableView.
I saw it in several News Feed applications:
Does anyone know this, please help me, thanks!
Use a UIRefreshControl
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"News Feed";
self.allNewsEntries = [NSMutableArray array];
[self downloadNewsEntries];
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(refreshContent)
forControlEvents:UIControlEventValueChanged];
self.refreshControl = refreshControl;
}
-(void) refreshContent {
[self.allNewsEntries removeAllObjects];
[self downloadNewsEntries];
[self.refreshControl endRefreshing];
}
Im try the pull down to refresh in collection view but im use the (tableview pull down to refresh controller)same code for collection view. Please any one help my problem.
Firstly you can write this code in your viewDidLoad :-
- (void) viewDidLoad
{
[super viewDidLoad];
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
refreshControl.tintColor = [UIColor blackColor];
refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:#"Pull to Refresh"];
[refreshControl addTarget:self action:#selector(refreshControlAction) forControlEvents:UIControlEventValueChanged];
[collectionView addSubview:refreshControl];
}
Now add a target
- (void) refreshControlAction
{
// Enter your code for request you are creating here when you pull the collectionView. When the request is completed then the collectionView go to its original position.
}