My UICollectionView has a UIImageView with autolayout constraints. I require a fixed number of cells in a row so need to scale the image if cell requires.
Even if I do not resize the cells, but set UIimageView in storyboard larger than the cells expected dimension the first time cell is populated the image size is incorrect, however when each cell is reused afterwards they scale perfectly.
The scaling works once cells are reused, but please what am I missing?
example view is the second call to reloaddata on the 'balls' lower middle of view. The first call filled the first 4 cells. The second call corrects the now reused cells, but fails to scale the 4 new cells content.
Below is some code as requested. generalBreakCollection is in focus :
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
if (collectionView == self.p1HiBreakCollection) {
breakBallCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"P1Cell" forIndexPath:indexPath];
UIImageView *collectionImageView = (UIImageView *)[cell viewWithTag:106];
ballShot *selectedBall = [self.p1BreakBalls objectAtIndex:indexPath.row];
cell.ball = [self.p1BreakBalls objectAtIndex:indexPath.row];
collectionImageView.image = [UIImage imageNamed:selectedBall.imageNameLarge];
return cell;
} else if (collectionView == self.p2HiBreakCollection) {
breakBallCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"P2Cell" forIndexPath:indexPath];
UIImageView *collectionImageView = (UIImageView *)[cell viewWithTag:108];
ballShot *selectedBall = [self.p2BreakBalls objectAtIndex:indexPath.row];
cell.ball = [self.p2BreakBalls objectAtIndex:indexPath.row];
collectionImageView.image = [UIImage imageNamed:selectedBall.imageNameLarge];
return cell;
} else {
// generalBreakCollection
breakBallCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"GeneralCell" forIndexPath:indexPath];
ballShot *selectedBall = [self.breakShots objectAtIndex:indexPath.row];
cell.ball = [self.breakShots objectAtIndex:indexPath.row];
cell.ballStoreImage.image = [UIImage imageNamed:selectedBall.imageNameLarge];
cell.ballStoreImage.highlightedImage = [UIImage imageNamed:[NSString stringWithFormat:#"highlighted_%#",selectedBall.imageNameLarge]];
cell.ballStoreImage.contentMode = UIViewContentModeScaleAspectFit;
return cell;
}
}
The resize block contains:
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
if (collectionView == self.generalBreakCollection) {
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
float cellWidth = screenWidth / 10.0; //Replace the divisor with the column count requirement. Make sure to have it in float.
CGSize size = CGSizeMake(cellWidth, cellWidth);
return size;
}
else {
CGSize defaultSize = [(UICollectionViewFlowLayout*)collectionViewLayout itemSize];
return defaultSize ;
}
}
I have my own UICollectionViewCell class with a UIImageView property ballStoreImage. I do not do so much with it, but I have linked it to the UIImageView inside the cell in the storyboard:
#property (strong, nonatomic) IBOutlet UIImageView *ballStoreImage;
The autolayout was not getting recognised until I added the code line:
[[cell contentView] setFrame:[cell bounds]];
So full block reads:
} else {
breakBallCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"breakCell" forIndexPath:indexPath];
[[cell contentView] setFrame:[cell bounds]];
ballShot *selectedBall = [self.breakShots objectAtIndex:indexPath.row];
cell.ball = [self.breakShots objectAtIndex:indexPath.row];
cell.ballStoreImage.image = [UIImage imageNamed:selectedBall.imageNameLarge];
cell.ballStoreImage.highlightedImage = [UIImage imageNamed:[NSString stringWithFormat:#"highlighted_%#",selectedBall.imageNameLarge]];
return cell;
}
Related
I am build a media edit project that allow user do edit with several media.To meet this need,I push a UICollectionView in a UICollectionViewCell.
The inner UICollectionView load a movie's thumb images.
sample code:
- (void)setupUI
{
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flowLayout.minimumInteritemSpacing = 0;
flowLayout.minimumLineSpacing = 0;
// flowLayout.itemSize = CGSizeMake(100, 200);
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
self.collectionView = collectionView;
collectionView.backgroundColor = [UIColor clearColor];
[self addSubview:collectionView];
collectionView.showsHorizontalScrollIndicator = NO;
collectionView.scrollEnabled = NO;
collectionView.userInteractionEnabled = NO;
// [collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.edges.equalTo(self);
// }];
collectionView.delegate = self;
collectionView.dataSource = self;
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cell"];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
PLog(#"count - %ld",self.videoItem.thumbnails.count);
return self.thumbImages.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
PLog(#"kkkkkkkkkkk,cell item %ld,cell address %#",indexPath.item,cell);
UIImage *image = self.thumbImages[indexPath.item];
if ([image isKindOfClass:[NSNull class]]) {
image = [UIImage imageWithColor:[UIColor blackColor]];
}
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[cell addSubview:imageView];
// imageView.userInteractionEnabled = YES;
[imageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(cell);
}];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(_videoItem.thumbWidth, CollectionHeight);
}
The outer UICollectionView data source from several different movie, custom UICollectionViewLayout
sample code:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = nil;
PDVideoItemCollectionViewCell *videoCell = [_collectionView dequeueReusableCellWithReuseIdentifier:#"reuse" forIndexPath:indexPath];
PLog(#"indexrow - %ld",indexPath.item);
if (videoCell.collectionView == nil) {
[videoCell setupUI];
}
videoCell.videoItem = [self.timelineItems objectAtIndex:indexPath.item];
videoCell.videoItem.videoCell = videoCell;
[videoCell reloadCollectionData];
PLog(#"cellll - %#",videoCell);
cell = videoCell;
cell.backgroundColor = MainBackgroundColor;
return cell;
}
Debug console log:
[PDVideoItem.m:172] image - <UIImage: 0x1268a3780>, {280, 158}--46
[PDVideoItem.m:172] image - <UIImage: 0x12689b800>, {280, 158}--47
[PDVideoItem.m:172] image - <UIImage: 0x12690a000>, {280, 158}--48
[PDVideoItem.m:172] image - <UIImage: 0x126821b60>, {280, 158}--49
[PDVideoItem.m:172] image - <UIImage: 0x1268a43d0>, {280, 158}--50
[PDVideoItem.m:184] done
[PDVideoItemCollectionViewCell.m:144] count - 51
[PDVideoItemCollectionViewCell.m:151] kkkkkkkkkkk,cell item 0,cell address <UICollectionViewCell: 0x12692de30; frame = (0 0; 112.5 63.2812); layer = <CALayer: 0x12691ff80>>
[PDVideoItemCollectionViewCell.m:151] kkkkkkkkkkk,cell item 1,cell address <UICollectionViewCell: 0x126930930; frame = (112.5 0; 112.5 63.2812); layer = <CALayer: 0x12692f310>>
[PDVideoItemCollectionViewCell.m:151] kkkkkkkkkkk,cell item 2,cell address <UICollectionViewCell: 0x1263aab60; frame = (225 0; 112.5 63.2812); layer = <CALayer: 0x12688f230>>
[PDVideoItemCollectionViewCell.m:151] kkkkkkkkkkk,cell
enter image description here
Situation description:2 movie = 2 outer UIcollectionViewCell = 2 inner UIcollectionView,total 82 thumbs = 82 inner UIcollectionViewCell
kkkkkkkkkkk log in collectionView: cellForItemAtIndexPath: method,count 25
Now get the problem that the inner UIcollectionViewCell seems do not ReUse,the memory will keep increase and UI load will be slow when I use UIPinchGestureRecognizer to do timeline scale.And the inner UICollectionView's delegate method collectionView: cellForItemAtIndexPath: never invoke when I do scroll action
Uh,Actually I think the main problem is I have generated all movies thumbs at first time,but because of inner collectionViewCell do not reuse,I couldn't generate thumb according to Item Indexpath.
This project refer to Apple's application iMovie a lot,maybe the applicate situation I describe is not clear,just download iMovie
Hope your good idea.
First you have a memory issue for the inner UICollectionView which that you add the UIImageView subview even if it's already added to the view's hierarchy here:
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[cell addSubview:imageView];
So you have to replace it with the following:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
PLog(#"kkkkkkkkkkk,cell item %ld,cell address %#",indexPath.item,cell);
UIImage *image = self.thumbImages[indexPath.item];
if ([image isKindOfClass:[NSNull class]]) {
image = [UIImage imageWithColor:[UIColor blackColor]];
}
UIImageView *imageView;
if ([cell viewWithTag: ImageView_TAG]) {
imageView = [[UIImageView alloc] initWithImage:image];
imageView.tag = ImageView_TAG
[cell addSubview:imageView];
} else {
imageView = [cell viewWithTag: ImageView_TAG]
imageView.image = image
}
// imageView.userInteractionEnabled = YES;
[imageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(cell);
}];
return cell;
}
Then for outer UICollectionView, you have to assign the collection view to the videoCell in collectionView:cellForItemAtIndexPath like:
videoCell.collectioView = collectioView
This will save your memory and avoid the increasing of the memory by effective usage of reusing cells
Good Luck :)
I have a UICollectionView. No caching as I haven't needed to apply so far, only have sum of 7 different images, but possibly 40 cells. I am also not experienced in that method.
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
UIImageView *collectionImageView = (UIImageView *)[cell viewWithTag:102];
UILabel *ballLabel = (UILabel *)[cell viewWithTag:103];
UILabel *ballLabelInfo = (UILabel *)[cell viewWithTag:110];
ballShot *selectedBall = [self.statsView.visitBallShotCollection objectAtIndex:indexPath.row];
NSString *ballDetail;
NSString *labelInfo;
ballDetail = [NSString stringWithFormat:#"Foul"];
labelInfo = [NSString stringWithFormat:#"%#",[selectedBall getFoulTypeText:selectedBall.foulid]];
collectionImageView.image = [UIImage imageNamed:selectedBall.imageNameLarge];
ballLabel.text = ballDetail;
ballLabelInfo.text = labelInfo;
return cell;
}
I am able to save displayed content of UICollectionView with even the correct content size, but not whole content.
- (UIImage *) imageWithCollectionView:(UICollectionView *)collectionBreakView
{
CGSize widthHeight = CGSizeMake(collectionBreakView.contentSize.width, collectionBreakView.contentSize.height);
UIGraphicsBeginImageContextWithOptions(widthHeight, collectionBreakView.opaque, 0.0);
[collectionBreakView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
How can I obtain whole content and place into the UIImage? If caching is the answer can somebody please give me a starter in setting that up?
Thanks in advance.
- (void)showImageAtTableView:(UITableView *)tableView forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([tableView indexPathsForSelectedRows].count) {
if ([[tableView indexPathsForSelectedRows] indexOfObject:indexPath] != NSNotFound) {
//cell is expanded
CGFloat frameHeight = [[self.widthArray objectAtIndex:indexPath.row] floatValue];
CGFloat frameWidth = [[self.heightArray objectAtIndex:indexPath.row] floatValue];
//CGFloat yOrigin = [self configureHeightForRowAtIndexPath:indexPath];
CGRect imageFrame = CGRectMake(0,
12,
frameWidth,
frameHeight);
UIImageView *imageView = [[UIImageView alloc] initWithFrame:imageFrame];
imageView.image = [UIImage imageNamed:#"testImage.jpg"];
imageView.contentMode = UIViewContentModeCenter;
//configue which cell
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
[cell.contentView addSubview:imageView];
}
}
}
the code above is supposed to add a UIImageView to an existing UITableViewCell when tapped. this is the line that call that method (showImageAtTableView:forRowAtIndexPath) :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
{
[self updateTableView];
//get and show the image at selected cell
[self showImageAtTableView:tableView forRowAtIndexPath:indexPath];
}
but this is the result when the tableviewcell is tapped:
http://imgur.com/4NMJLf6,XweOgQu
what did I do wrong?
You're not changing the height of the UITableViewCell.
I think a better approach would be to include the UIImageView in the xib / storyboard design. Assuming you have some kind of dto object storing the data showed in the cells, you can keep on them a boolean indicating whether or not the image should be showed.
On your didSelectRowAtIndexPath you'll update that boolean, and do a [tableView reloadData].
In your cellForRowAtIndexPath you'll hide / show the UIImageView according the boolean.
In your heightForRowAtIndexPath you'll check again the boolean value in order to update the height accordingly.
Hope it helps.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Set the data for this cell:
cell.textLabel.text = [namesArray objectAtIndex:indexPath.row];
cell.textLabel.textColor = [UIColor grayColor];
cell.textLabel.font = [UIFont fontWithName:#"Trebuchet MS" size:14];
cell.textLabel.textAlignment = UITextAlignmentLeft;
cell.imageView.image = [UIImage imageNamed:[imagesArray objectAtIndex:indexPath.row ]];
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 5, 5)];
imgView.image = [UIImage imageNamed:[imagesArray objectAtIndex:indexPath.row ]];
cell.imageView.image = imgView.image;
[cell.imageView setFrame:CGRectMake(0, 0, 55, 55)];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
return cell;
}
Here I'm using just TableView not UITableViewCell, but I want to resize images on TableView. I've taken a look at many examples on the internet, however I don't understand how any of them work - I'm not able to get them resized on TableView. Could someone explain how to get it working? [cell.imageView setFrame:CGRectMake(0, 0, 55, 55)]; is not working
Here i put logic of both Crop and resize image, use it as per your requirement.
For Get Cropped Image:
UIImage *croppedImg = nil;
CGRect cropRect = CGRectMake(AS YOu Need); // set frame as you need
croppedImg = [self croppIngimageByImageName:self.imageView.image toRect:cropRect];
The following method that return UIImage (as You want size of image)
- (UIImage *)croppIngimageByImageName:(UIImage *)imageToCrop toRect:(CGRect)rect
{
//CGRect CropRect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height+15);
CGImageRef imageRef = CGImageCreateWithImageInRect([imageToCrop CGImage], rect);
UIImage *cropped = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return cropped;
}
Here you get Croped Image that return by above method;
OR RESIZING
And also use following method with specific hight and width of image for Resizing:
+ (UIImage*)resizeImage:(UIImage*)image withWidth:(CGFloat)width withHeight:(CGFloat)height
{
CGSize newSize = CGSizeMake(width, height);
CGFloat widthRatio = newSize.width/image.size.width;
CGFloat heightRatio = newSize.height/image.size.height;
if(widthRatio > heightRatio)
{
newSize=CGSizeMake(image.size.width*heightRatio,image.size.height*heightRatio);
}
else
{
newSize=CGSizeMake(image.size.width*widthRatio,image.size.height*widthRatio);
}
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
This method return NewImage, with specific size that you want.
If you want to customize the aspect of the cell (for example the size of the image view) you need to use a custom UITableViewCell. Currently you are using a standard cell UITableViewCellStyleDefault which doesn't let you customize the size of the image view.
Create an UITableViewCell in storyboard or in a Xib file, add it your image view and set its tag to a number. After that you need to retrieve the cell for configuring it:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UIImageView *imageView = (UIImageView *) [cell viewWithTag:TAG_NUMBER];
// do your stuff
return cell;
}
Maybe you can do something like this. Just add a new imageView under the cell's contentView atleast it will be easier for you to set the frame.
And just to clarify you are already using UITableviewCell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// Create a new imageview to have your desired frame
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 5, 5)];
// Add tag
imgView.tag = 100;
// Add the imageView to the contentView of the cell
[cell.contentView addSubview:imgView];
}
// Other codes
UIImageView *imageV = (UIImageView *)[cell.contentView viewWithTag:100];
// Assign Image here
imageV.image = [UIImage imageNamed:[imagesArray objectAtIndex:indexPath.row ]];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
return cell;
}
I'm new building UICollectionView and I have an issue. I would like to display images that have 300px width and calculate the right height scale. To do this, I did :
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [cv dequeueReusableCellWithReuseIdentifier:#"MyCell" forIndexPath:indexPath];
UIImage *image = [photos objectAtIndex:indexPath.row];
if(image){
UIImageView *imageView = [[UIImageView alloc]initWithImage:image];
float scale = (image.size.height/image.size.width)*300;
[imageView setFrame:CGRectMake(imageView.frame.origin.x, imageView.frame.origin.y, 300, scale )];
[cell addSubview:imageView];
cell.backgroundColor = [UIColor clearColor];
}else{
cell.backgroundColor = [UIColor redColor];
}
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
UIImage *image = [photos objectAtIndex:indexPath.row];
float scale = (image.size.height/image.size.width)*300;
return CGSizeMake(300, scale);
}
This seems to work at the beginning but as soon as I scroll down, images start to overlap each others. Is that any way to avoid this ?
You have to resize cells in UICollectionView, use UICollectionViewFlowLayout
Check out the Ray Wenderlich Tutorial: http://www.raywenderlich.com/22324/beginning-uicollectionview-in-ios-6-part-12