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.
Related
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
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.
So I built a custom animation that makes the cell go off screen to the left (similar to how deleteRowsAtIndexPaths: with UITableViewRowAnimationLeft looks). I did this because if i try to bulk delete(delete all rows in the table) using the classic method(deleteRowsAtIndexPaths: with UITableViewRowAnimationLeft) does not look right. Now my custom animation looks and works great. I have different menu buttons that first clear the table using my animation and it works great. The thing is I want the same animation to kick in when i select a cell in the table but for some reason it just doesn't work (no animations kick in). Here's the animation code tho it should be redundant(this code get's called for each cell-- from the last to the first row):
NSIndexPath *ip = [NSIndexPath indexPathForRow:i inSection:0];
UITableViewCell *cell = [_table cellForRowAtIndexPath:ip];
CGRect newFrame;
if(i%2==0){
newFrame = cell.frame;
newFrame.origin.x = -[UIScreen mainScreen].bounds.size.width;
}else{
newFrame = cell.frame;
newFrame.origin.x = [UIScreen mainScreen].bounds.size.width;
}
[UIView animateWithDuration:0.2 delay:0 options:0
animations:^{cell.frame = newFrame;}
completion: ^(BOOL finished){
//[cell removeStatus];
if(i == 0){
[dataSource removeAllObjects];
[_table reloadData];
}
}];
I found a workaround to this question. I switched the animations to basic animation and now it works.
Theoretically the following code should animate the table view cell of the screen to the right and bring in a dark "view" in it's place.
CGPoint location = [gesture locationInView:tableView];
NSIndexPath *swipedIndexPath = [tableView indexPathForRowAtPoint:location];
UITableViewCell *swipedCell = [tableView cellForRowAtIndexPath:swipedIndexPath];
//code to create view
UIView *sideView;
sideView.backgroundColor = [UIColor lightGrayColor];
//set the side view frame to the same as the cell
sideView.frame = swipedCell.frame;
//add it to the tableview
[tableView addSubview:sideView];
[UIView animateWithDuration:1
animations:^{
sideView.frame = CGRectMake(0, swipedCell.frame.origin.y, swipedCell.frame.size.width, swipedCell.frame.size.height);
// While simultaneously moving the cell's frame offscreen
// The net effect is that the side swipe view is pushing the cell offscreen
swipedCell.frame = CGRectMake(swipedCell.frame.size.width, swipedCell.frame.origin.y, swipedCell.frame.size.width, swipedCell.frame.size.height); //move cell off
}];
However, only the cell moves off the screen. No gray view comes in it's place.
Is there a step I am missing? What is wrong with this code?
Video of example here
The big error is that you're not initializing sideView to anything.
Try UIView* sideview = [[UIView alloc] initWithFrame:swipedCell.frame];
It doesn't sound like a good idea to add a view in place of a cell just like that. You'd have to deal with scrolling, table view editing, and other stuff that the UITableView takes care of for you. So instead, try adding the sideView as a subview of swipedCell.contentView and then doing this animation instead:
[UIView animateWithDuration:1 animations:^{
sideView.frame = CGRectMake(0, swipedCell.frame.origin.y, swipedCell.frame.size.width, swipedCell.frame.size.height);
//This moves all the subviews except for the sideView off the screen
for (UIView *subview in swipedCell.contentView.subviews)
if (![subview isEqual:sideView])
subview.frame = CGRectOffset(subview.frame, swipedCell.frame.size.width, 0.0);
}];
Hope this helps!
I'm trying to animate two table cells background colors from red back to the original color, white.
The following code is what I'm using. The problem is that it never shows the red color -- it simply animates from (original) white to (animated-to) white. I.e., if I change the color in the animation block, it will animate to that color.
[table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].backgroundColor = [UIColor redColor];
[table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]].backgroundColor = [UIColor redColor];
[UIView animateWithDuration:0.8 delay:0.2 options:UIViewAnimationOptionCurveEaseInOut animations:^{
[table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].backgroundColor = [UIColor whiteColor];
[table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]].backgroundColor = [UIColor whiteColor];
}
completion:^(BOOL finished) {
}];
The following code works as expected for the table's background, but that's not what I want:
table.backgroundColor = [UIColor redColor];
[UIView animateWithDuration:0.8 delay:0.2 options:UIViewAnimationOptionCurveEaseInOut animations:^{
table.backgroundColor = [UIColor clearColor];
}
completion:^(BOOL finished) {
}];
So, why doesn't my cell background animate when my table background does?
For what it's worth, I have a bunch of other chained animations I perform on the table view right after this, but having commented those animations out, I still have this issue.
Because a cell contains other views. You have to check the color of cell.contentView, cell.accessoryView and cell.backgroundView. If all of these are [UIColor clearColor], you can just animate cell.backgroundColor.
It looks like #Jason Coco is right. I can't do it (cleanly and quickly):
From Apple:
Note: If you want to change the background color of a cell (by setting
the background color of a cell via the backgroundColor property
declared by UIView) you must do it in the
tableView:willDisplayCell:forRowAtIndexPath: method of the delegate
and not in tableView:cellForRowAtIndexPath: of the data source.
Changes to the background colors of cells in a group-style table view
has an effect in iOS 3.0 that is different than previous versions of
the operating system. It now affects the area inside the rounded
rectangle instead of the area outside of it.
Reference
So if I really wanted to I'd have to set some variable, then call reloadData on the table or something similar.