UITableView does not PROPERLY scroll to bottom programmatically - ios

I have a 100-row table and want to scroll it programmatically to any element and select that element. In first controller I specify row and section and push the controller with the UITableView onto navigation stack. In viewWillAppear of "tableView-controller" I use the code:
[tableView_ selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section] animated:NO scrollPosition:UITableViewScrollPositionMiddle];
The curious part is, it scrolls perfectly to any of 99 first rows, 100-th row gets selected, but remains "below" the visible area. I have to scroll the table manually to reveal it.
If I place that code in viewDidAppear, table scrolls nicely, but after a noticeable delay.
What did I also try:
Reducing the height of tableView. I got tableView which partly covers the screen with last row obscured indeed.
Playing with contentSize - setting its height to small large values - no luck.
Setting contentInset.bottom - worked, but I've got a useless space at the bottom.
In viewDidAppear, processing 99 rows as usual and setting custom contentOffset for the 100-th row:
offset.y += tableView_.contentSize.height - tableView_.bounds.size.height + 44;
worked too, but it seems to be an ugly way.
So, what should I do to get my tableView pre-scrolled even to 100-th element when "tableView-controller" appears?
UPDATE.
I do not use any xibs or storyboards, just defining views in viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
tableView_ = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStyleGrouped];
tableView_.dataSource = self;
tableView_.delegate = self;
tableView_.sectionFooterHeight = 0.0f;
self.view = tableView_;
numbers = [NSMutableDictionary dictionary];
numberSectionTitles = [NSMutableArray array];
//... some model initialization
headerView = [[UIView alloc] initWithFrame:(CGRect){0, 0, 320, 60}];
headerView.backgroundColor = [UIColor greenColor];
UILabel *l = [[UILabel alloc] initWithFrame:(CGRect){20, 20, 280, 20}];
l.textColor =[UIColor whiteColor];
l.tag = 121;
[headerView addSubview:l];
}
And adjust selection in viewDidAppear (dirty workarounds)
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
int row = _selectedIndex % 10;
int section = (_selectedIndex - row) / 10;
if(row == 9 && section == 9){
CGSize contentSize = tableView_.contentSize;
CGPoint offset = tableView_.contentOffset;
offset.y += tableView_.contentSize.height - tableView_.bounds.size.height + 44;
tableView_.contentOffset = offset;
}
[tableView_ selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section] animated:NO scrollPosition:UITableViewScrollPositionMiddle];
}

may be your view height is not same of tableview. your superview(on which you are adding your tableview) should be same. your last row is hiding because your view is not as same height as your tableview,may be this solve your problem.

You can do it manually:
[_tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section] animated:NO scrollPosition:UITableViewScrollPositionNone];
CGRect rect = [_tableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section]];
CGFloat offsetY = rect.origin.y+rect.size.height/2-_tableView.frame.size.height/2-_tableView.contentInset.top/2;
if (offsetY < -_tableView.contentInset.top)
offsetY = -_tableView.contentInset.top;
else if (offsetY > _tableView.contentSize.height-_tableView.frame.size.height)
offsetY = _tableView.contentSize.height-_tableView.frame.size.height;
_tableView.contentOffset = CGPointMake(_tableView.contentOffset.x, offsetY);

if (cell==nil)
if you've written an if statement like this in your CellforRowatIndexpath remove that particular if statement and proceed. That line causing problem
Enjoy coding

Related

Getting black screen when app returning from background

I'm dealing with a tricky bug on my app. I have a chat view controller where I deal with keyboard showing and hiding. But the weird part is when putting the app on background.
This is the view controller before going to background (tapping the home button)
And this is the app when returning from background
If I put the app on background using the home button, the black screen only appears for a second, but if I block the phone and then unlock, the black screen keeps there.
This is how I deal with the keyboard
- (void)keyboardWillShowWithRect:(CGRect)rect
{
//We adjust inverted insets because tableview will be inverted
CGFloat displacementDistance = rect.size.height - self.composeBarView.bounds.size.height;
self.tableView.contentInset = UIEdgeInsetsMake(self.composeBarView.bounds.size.height, 0, displacementDistance, 0);
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y - displacementDistance, self.view.frame.size.width, self.view.frame.size.height)];
}
- (void)keyboardWillDismissWithRect:(CGRect)rect
{
//We adjust inverted insets because tableview will be inverted
CGFloat displacementDistance = rect.size.height - self.composeBarView.bounds.size.height;
self.tableView.contentInset = UIEdgeInsetsMake(self.composeBarView.bounds.size.height, 0, 0, 0);
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y + displacementDistance, self.view.frame.size.width, self.view.frame.size.height)];
}
The tableView used to display the messages is inverted in order to display the first message at the bottom. Here's how I do it:
- (void)setupTableView
{
self.tableView.delegate = self;
self.tableView.dataSource = self;
//We adjust inverted insets because tableview will be inverted
self.tableView.contentInset = UIEdgeInsetsMake(self.composeBarView.bounds.size.height, 0, 0, 0);
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 500.0;
self.tableView.sectionFooterHeight = 30.0;
self.tableView.showsVerticalScrollIndicator = NO;
[self.tableView registerNib:[UINib nibWithNibName:#"MessagesDateHeader" bundle:nil] forHeaderFooterViewReuseIdentifier:#"MessagesDateHeader"];
// Table View is inverted so we display last messages at the bottom instead of top
self.tableView.transform = CGAffineTransformMakeRotation(-M_PI);
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(didTapOnTableView)];
tap.numberOfTapsRequired = 1;
[self.tableView addGestureRecognizer:tap];
}
Also, I have self.definesPresentationContext = YES; set on viewDidLoad
Anyone can give me a hint of what's happening?
Thanks
I used to have a similar problem. Issue was the resizing of the tableView when keyboard appears/disappears based on its frame.
What I did was set a constraint between the bottom of the tableView and the superView and then change its constant with the appearance/disappearance of the keyboard.
Instead of relying on keyboardWillShowWithRect: and keyboardWillDismissWithRect: you can use listen to UIKeyboardWillChangeFrameNotification and handle it like follows
- (void) keyboardWillChangeFrame:(NSNotification *)notification {
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardFrameEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardFrameEnd = [self.view convertRect:keyboardFrameEnd toView:nil];
[UIView animateWithDuration:[userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]
delay:0.f
options:[userInfo[UIKeyboardAnimationCurveUserInfoKey] intValue] << 16
animations:^{
self.bottomConstraint.constant = CGRectGetHeight(self.view.frame) - keyboardFrameEnd.origin.y;
[self.view layoutIfNeeded];
} completion:nil];
}
[self.view layoutIfNeeded] is used so that view shows the whole animation

iOS - UICollectionView shadow flickers while reloading the cell

In my collection view I have added a custom view with shadow in the collection cell.
I added shadow to the view by using the following code.
cell.shadowView.backgroundColor = [UIColor greenColor];
cell.shadowView.layer.masksToBounds = NO;
cell.shadowView.layer.shadowColor = [UIColor redColor].CGColor;
cell.shadowView.layer.shadowOffset = CGSizeMake(-2.0f, 2.0f);
cell.shadowView.layer.shadowOpacity = 1.0f;
cell.shadowView.layer.shadowRadius = 4.0f;
cell.shadowView.layer.shouldRasterize = YES;
cell.shadowView.layer.rasterizationScale = [UIScreen mainScreen].scale;
Whenever I reload the cell the reloaded cell flickers every time.
Following code I used for reloading the cell.
[self.collectionView performBatchUpdates:^{
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:1 inSection:0];
NSArray* indexPathArray = [NSArray arrayWithObjects:indexPath, nil];
[self.collectionView reloadItemsAtIndexPaths:indexPathArray];
} completion:nil];
I want to avoid this flickering when reloading the cell.
I can avoid the flickering by running the performBatchUpdates call inside [UIView performWithoutAnimation:^{}] animation block. But it causes breakage in the existing animation code.
Is there any way to avoid this flickering issue?
Thank you.

UITable view scrolled up by half of UISectionHeader

I have a problem that My UITableView is always scrolled up by maybe the half of Section Header.
I have a custom Section Header which is 44 pixel height.
After a scrolling down and release the focus the table view gets to his good position. The bug happes only after init.
here is my viewDidLoad code :
[self.tableView removeUsslessSeparators];
[self.tableView setEstimatedRowHeight:50];
[self.tableView setEstimatedSectionHeaderHeight:0];
[self.tableView setSectionIndexColor:[UIColor colorWithHexString:#"#000000"]];
[self.tableView setSectionIndexBackgroundColor:[UIColor whiteColor]];
[self.tableView setRowHeight:UITableViewAutomaticDimension];
[self.tableView setSectionHeaderHeight:UITableViewAutomaticDimension];
[self.tableView registerNib:[VOIOrbitContactsListSectionHeader nibRepresentation] forHeaderFooterViewReuseIdentifier:[VOIOrbitContactsListSectionHeader preferredIdentifier]];
[self.tableView registerNib:[VOIOrbitContactCell nibRepresentation] forCellReuseIdentifier:[VOIOrbitContactCell preferredIdentifier]];
self.searchBarController = [VOISearchBarController searchViewControllerWithDelegate:self];
[self containerAddChildViewController:self.searchBarController toContainerView:self.searchControllerContainer useAutolayout:YES];
[self.searchControllerContainerTopOffsetConstraint setConstant:75];
[self.tableViewTopOffsetConstraint setConstant:self.searchControllerContainerTopOffsetConstraint.constant + 4] ;
[self.tableView setContentInset:UIEdgeInsetsMake( self.searchControllerContainerHeightConstraint.constant , 0, 50, 0)];
// CGPoint offset = self.tableView.contentOffset;
// self.tableView.contentOffset = offset;
// [self.tableView setContentOffset:CGPointZero animated:NO];
[self checkIfPlusButtonNeedsToBeHidden];
[NSNotificationCenter addObserverForName:VOCChangeNotificationNameForEntity([VOCOrbit class]) usingBlock:^(NSNotification *note) {
[self.tableView reloadData];
}];
I was trying to use different solutions to scroll down a bit the table view programatically. but none of them works.
[self.searchControllerContainerTopOffsetConstraint setConstant:75];
[self.tableViewTopOffsetConstraint setConstant:self.searchControllerContainerTopOffsetConstraint.constant + 4] ;
Dont use the content offsets rather give the position of the table directly to:
[self.table setframe:CGRectMake(0,0,width,height)];
Then, Pass your header frame as Header Of Table
table.tableHeaderView = yourHeaderView;
Hope, this will work for you.

iOS - Facebook POP: slide tableview cell to bottom right corner

Maybe you can help me with a problem.
I'm using the new Facebook POP animation framework in an iOS (7) app.
I have a tableview with a "+ button" in each cell. I want that if a user clicks on a button in the cell, that the cell (a copy of that cell) slides to the bottom right corner (in the last tabbar item) from alpha 1 to 0. Like a "add to cart" button. So the user knows that the row is added to the cart.
Does anyone know how I can accomplish that with the Facebook POP framework? Or can you point me in the right direction?
I think it's not so difficult, but I can't figure it out.
Many thanks in advance!
Assuming you refer to a UITableView inside a UIViewController which is assigned as a tab of a UITabBarController, first you duplicate the selected cell into a UIView and then you perform basic POP animation as follows:
#import <math.h>
#import "POPAnimation.h"
#import "POPBasicAnimation.h"
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UIView *view = [self duplicateCell:cell
ContentOffset:tableView.contentOffset
Row:indexPath.row];
[self.view addSubview:view];
NSUInteger numberOfTabs = 3;
CGFloat tabWidth = self.view.frame.size.width / numberOfTabs;
[self fadeOutView:view WhileMoveTo:CGRectMake(self.view.frame.size.width - tabWidth,
tableView.frame.size.height,
tabWidth,
view.frame.size.height)];
}
- (UIView*)duplicateCell:(UITableViewCell*)cell ContentOffset:(CGPoint)offset Row:(NSInteger)row
{
CGFloat cellHeight = cell.frame.size.height;
CGFloat topVisibleCellRow = (int)(offset.y / cellHeight) ;
CGFloat delta = fmodf(offset.y, cellHeight);
CGRect frame = cell.frame;
frame.origin.y = (row - topVisibleCellRow)*cellHeight - delta;
UIView *view = [[UIView alloc] initWithFrame:frame];
view.backgroundColor = [UIColor yellowColor];
UILabel *label = [[UILabel alloc] initWithFrame:cell.textLabel.frame];
label.textColor = [UIColor blackColor];
label.text = cell.textLabel.text;
label.contentMode = UIViewContentModeScaleAspectFit;
[view addSubview:label];
return view;
}
- (void)fadeOutView:(UIView*)view WhileMoveTo:(CGRect)rect
{
[view pop_removeAllAnimations];
POPBasicAnimation *animFrame = [POPBasicAnimation animationWithPropertyNamed:kPOPViewFrame];
POPBasicAnimation *animAlpha = [POPBasicAnimation animationWithPropertyNamed:kPOPViewAlpha];
CGFloat fDuration = 1.5f;
animFrame.toValue = [NSValue valueWithCGRect:rect];
animFrame.duration = fDuration;
animAlpha.toValue = #(0.0);
animAlpha.duration = fDuration;
[view pop_addAnimation:animFrame forKey:#"animateFrame"];
[view pop_addAnimation:animAlpha forKey:#"animateAlpha"];
}
This example is based on a basic UITableViewCell but you can adapt the cell duplication to any custom cell scheme.

UICollectionView full screen zoom on UICollectionViewCell

How can you zoom in on a UICollectionViewCell so that it will be displayed full screen? I have extended UICollectionViewFlowLayout and in my view controller when a cell is tapped I'm doing this:
CGPoint pointInCollectionView = [gesture locationInView:self.collectionView];
NSIndexPath *selectedIndexPath = [self.collectionView indexPathForItemAtPoint:pointInCollectionView];
UICollectionViewCell *selectedCell = [self.collectionView cellForItemAtIndexPath:selectedIndexPath];
NSLog(#"Selected cell %#", selectedIndexPath);
Not really sure where to go from here. Should the UICollectionView be responsible of showing the zoomed in cell? Or should I create a new view controller that displays the content of the cell (an image) in full screen?
I took the solution here and modified it slightly to work with a collection view instead. I also added a transparent gray background to hide the original view a bit (assuming the image doesn't take up the entire frame).
#implementation CollectionViewController
{
UIImageView *fullScreenImageView;
UIImageView *originalImageView;
}
...
// in whatever method you're using to detect the cell selection
CGPoint pointInCollectionView = [gesture locationInView:self.collectionView];
NSIndexPath *selectedIndexPath = [self.collectionView indexPathForItemAtPoint:pointInCollectionView];
UICollectionViewCell *selectedCell = [self.collectionView cellForItemAtIndexPath:selectedIndexPath];
originalImageView = [selectedCell imageView]; // or whatever cell element holds your image that you want to zoom
fullScreenImageView = [[UIImageView alloc] init];
[fullScreenImageView setContentMode:UIViewContentModeScaleAspectFit];
fullScreenImageView.image = [originalImageView image];
// ***********************************************************************************
// You can either use this to zoom in from the center of your cell
CGRect tempPoint = CGRectMake(originalImageView.center.x, originalImageView.center.y, 0, 0);
// OR, if you want to zoom from the tapped point...
CGRect tempPoint = CGRectMake(pointInCollectionView.x, pointInCollectionView.y, 0, 0);
// ***********************************************************************************
CGRect startingPoint = [self.view convertRect:tempPoint fromView:[self.collectionView cellForItemAtIndexPath:selectedIndexPath]];
[fullScreenImageView setFrame:startingPoint];
[fullScreenImageView setBackgroundColor:[[UIColor lightGrayColor] colorWithAlphaComponent:0.9f]];
[self.view addSubview:fullScreenImageView];
[UIView animateWithDuration:0.4
animations:^{
[fullScreenImageView setFrame:CGRectMake(0,
0,
self.view.bounds.size.width,
self.view.bounds.size.height)];
}];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(fullScreenImageViewTapped:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[fullScreenImageView addGestureRecognizer:singleTap];
[fullScreenImageView setUserInteractionEnabled:YES];
...
- (void)fullScreenImageViewTapped:(UIGestureRecognizer *)gestureRecognizer {
CGRect point=[self.view convertRect:originalImageView.bounds fromView:originalImageView];
gestureRecognizer.view.backgroundColor=[UIColor clearColor];
[UIView animateWithDuration:0.5
animations:^{
[(UIImageView *)gestureRecognizer.view setFrame:point];
}];
[self performSelector:#selector(animationDone:) withObject:[gestureRecognizer view] afterDelay:0.4];
}
-(void)animationDone:(UIView *)view
{
[fullScreenImageView removeFromSuperview];
fullScreenImageView = nil;
}
You can simply use another layout (similar to the one you already have) wherein the item size is larger, and then do setCollectionViewLayout:animated:completion: on the collectionView.
You don't need a new view controller. Your datasource remains the same. You can even use the same cell Class, just make sure that it knows when to layout things for a larger cell content size, and when not to.
I'm quite sure that's how Facebook does it in Paper, as there is no reloading of the content, i.e. [collectionView reloadData] never seems to be called (would have caused flickering and resetting of the scroll offset, etc). This seems to be the most straight forward possible solution.
CGPoint pointInCollectionView = [gesture locationInView:self.collectionView];
NSIndexPath *selectedIndexPath = [self.collectionView indexPathForItemAtPoint:pointInCollectionView];
UICollectionViewCell *selectedCell = [self.collectionView cellForItemAtIndexPath:selectedIndexPath];
NSLog(#"Selected cell %#", selectedIndexPath);
__weak typeof(self) weakSelf = self;
[self.collectionView setCollectionViewLayout:newLayout animated:YES completion:^{
[weakSelf.collectionView scrollToItemAtIndexPath:selectedIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
}];
You can use MWPhotoBrowser, which is suitable for your problem. It supports Grid with Tap to Zoom functionality. you can get it from here
Grid
In order to properly show the grid of thumbnails, you must ensure the property enableGrid is set to YES, and implement the following delegate method:
(id <MWPhoto>)photoBrowser:(MWPhotoBrowser *)photoBrowser thumbPhotoAtIndex:(NSUInteger)index;
The photo browser can also start on the grid by enabling the startOnGrid property.

Resources