UITable view scrolled up by half of UISectionHeader - ios

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.

Related

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.

Animating the height change of a UICollectionView

I have a UICollectionView which is a subview of a UIScrollView (this is required because of stuff above and below the collection view.
Anyway...
The collection view shows three items per row and only two rows to begin with.
The first five items are actual items and the last item is a "See More" item.
When the last item is pressed I change the number of items shown and update the collection view...
NSMutableArray *indexPaths = [NSMutableArray array];
for (int i = 5 ; i<self.facilities.count ; i++) {
[indexPaths addObject:[NSIndexPath indexPathForItem:i inSection:0]];
}
// changing the tableCollapsed bool updates the number of items
if (self.isTableCollapsed) {
self.tableCollapsed = NO;
[self.collectionView insertItemsAtIndexPaths:indexPaths];
} else {
self.tableCollapsed = YES;
[self.collectionView deleteItemsAtIndexPaths:indexPaths];
}
I then run...
[self setHeightAnimated:YES];
Which does this...
- (void)setHeightAnimated:(BOOL)animated
{
NSInteger numberOfRows = (NSInteger) ceilf((CGFloat)[self getNumberOfItems] / self.numberOfItemsPerRow);
self.heightConstraint.constant = numberOfRows * self.rowHeight;
if (animated) {
[UIView animateWithDuration:0.2
animations:^{
[self layoutIfNeeded];
}];
} else {
[self layoutIfNeeded];
}
}
This always works and sets the right height and it gets the correct value of animated when it should be YES or NO. However, it never animates. It just switches to the new height immediately.
I'm guessing this is because of some layout code that is run or something but I was wondering if anyone knows how best to do this so that the height changes properly with the animation I have specified.
Thanks
OK! After a couple of hours I found a solution.
I have moved the insertion block into a method like this...
- (void)addItemsAtIndexPaths:(NSArray *)indexPaths {
[UIView performWithoutAnimation:^{
[self.collectionView insertItemsAtIndexPaths:indexPaths];
}];
[self setHeightAnimated:YES completion:nil];
}
This uses a method that I didn't know about the performWithoutAnimation to add items to the collection view. Then I animate the height independently of that.
Works like a charm.
The reverse works also...
- (void)removeItemsAtIndexPaths:(NSArray *)indexPaths {
[self setHeightAnimated:YES completion:^(BOOL finished) {
[UIView performWithoutAnimation:^{
[self.collectionView deleteItemsAtIndexPaths:indexPaths];
}];
}];
}
This animates the height first and then removes the items without animation.

UITableView does not PROPERLY scroll to bottom programmatically

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

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.

animating UITableViewHeader to grow/shrink

Im very new to iOS and am trying to figure out how I can animate the tableView header to appear like its sliding down from the top of the view, stay there for 3 seconds, then slide back up and disappear.
I havent done any animation of any kind before so I could really use some help. I dont know where to start. Ive looked at other answers on here but cant seem to figure out how to do it.
ive got my table view appearing just fine with this code in my viewDidLoad of my UITableViewController class
self.headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320,15)];
self.headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 15)];
self.headerLabel.textAlignment = NSTextAlignmentCenter;
self.headerLabel.text = #"some text";
[self.headerView addSubview:self.headerLabel];
self.tableView.tableHeaderView = self.headerView;
self.tableView.tableHeaderView.frame = CGRectMake(0, 0, 320, 15);
I assume I need to animate the height of my frame.
edit: I found this code which seems like it should work, however it crashes my app when the animation runs
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[UIView animateWithDuration:3.0f
delay:0.0f
options: UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.headerView.frame = CGRectMake(0.0f, 0.0f, 320.f, 0.0f);
}
completion:^(BOOL finished) {
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}];
}
I don't know if you can animate a table view's header view like you want to. With a complex UI object like a Table view Apple tends to treat the views that make up the object as private, and bad things tend to happen when you try to manipulate the view hierarch.
If you're not using auto-layout and you want to animate another view that is part of YOUR view hierarchy then your code might be as simple as something like this:
CGPoint center = myView.center;
CGFloat myViewBottom = myView.frame.origin.y + myView.frame.origin.size.height;
//Move the view above the top of it's superview before starting the animation.
center.y -= myViewBottom;
//Animate the view down into position
[UIView animateWithDuration: .2
animations:
^{
myView.center += myViewBottom;
};
completion:
^{
//As the completion block for the first animation, trigger another
//animation to animate the view away again. This time delay
//for 3 second before the 2nd animation.
[UIView animateWithDuration: .2
delay: 3.0
options: 0
animations:
^{
myView.center -= myViewBottom;
};
completion: nil
}
];
Try to use beginUpdates and endUpdates, here is an example:
in your header
#property NSInteger newOffset;
implementation:
- (void) colapseHeader
{
_newOffset = 50;
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 50 + _newOffset;
}
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
_newOffset = 100;
[self.tableView beginUpdates];
[self.tableView endUpdates];
[self performSelector:#selector(colapseHeader) withObject:nil afterDelay:3];
}

Resources