UICollectionView move specific cell - ios

I have a working sample of UICollectionView, I can move a cell [by indexPath], but I need a specific cell [indexpath.row?] So I move the cell i need, At the moment a cell moves but not the correct one, so
when I move for example
NSIndexPath *index = [indexPaths objectAtIndex:0];
the cell on indexpath.row = 3 moves, how to call the cell by indexpath row?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor lightGrayColor];
CGRect frame = CGRectMake(10, 100, 300, 500);
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
self.collectionView=[[UICollectionView alloc] initWithFrame:frame collectionViewLayout:layout];
[self.collectionView setDataSource:self];
[self.collectionView setDelegate:self];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[self.collectionView setBackgroundColor:[UIColor redColor]];
[self.view addSubview:self.collectionView];
UIButton *animus = [UIButton buttonWithType:UIButtonTypeRoundedRect];
animus.frame = CGRectMake(100, 20, 90, 30);
[animus setTitle:#"Animus" forState:UIControlStateNormal];
[animus addTarget:self action:#selector(animusPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:animus];
}
- (void)animusPressed:(id)sender
{
NSIndexPath *index = [indexPaths objectAtIndex:0]; //en el index!
NSLog(#"moving tha cell :: %d", index.row);
__weak UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:index]; // Avoid retain cycles
CGRect frame = cell.frame;
frame.origin.y = 300;
cell.frame = frame;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
cell.backgroundColor=[UIColor greenColor];
UILabel *title = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, cell.bounds.size.width, 40)];
[cell.contentView addSubview:title];
NSString *titleLbl = [NSString stringWithFormat:#"i = %d", indexPath.row];
title.text = titleLbl;
return cell;
}
So a cell moves, but not the one I want, I need to move a specific cell, by indexpath.row like it is shown on the cellForRow,
How to specify what cell I want to move?
Please note im moving cell on index = 0 , but the indexpath.row = 2 is the one moving
Thanks

Have you tried something like this?
[NSIndexPath indexPathForItem:0 inSection:0]

First of all, it will be more difficult to make any adjustments your UICollectionView without using an array as your data source. Most commonly, you will have one array holding data and in your cellForItemAtIndexPath: method you grab index-specific data from that array via:
MyData *myData = [self.arrayOfMyData objectAtIndex:indexPath.row];
This way you can populate the cell using data related to the current indexPath. Once you do that, just update your data array and then call:
[self.collectionView reloadData];
Then the updates will be represented in the collection view. If you want to animate those changes, use:
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadData];
} completion:nil];
If you want to "move" cells around with the appearance that it changed its original position, you could manage your arrayOfMyData to add a signifier at the index you want empty to set the background of the cell as clear and put the cell to move at the end of your array, then call reloadData.

Related

Fill UICollectionViewCells in UICollectionView with data from an array programmatically

I have a UICollectionView which I would like to populate it with 100 UICollectionViewCells each with its own unique UILabel with text fetched from an array. I'd like to do this programmatically (without the Storyboard).
I've attempted it as posted below, but for some reason only the first cell renders properly.
// Setting up the UICollectionView
- (void)setupCollectionView {
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
CGRect newFrame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height * 0.5);
self.collectionView=[[UICollectionView alloc] initWithFrame:newFrame collectionViewLayout:layout];
[self.collectionView setDataSource:self];
[self.collectionView setDelegate:self];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[self.collectionView setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:self.collectionView];
}
//Trying to generate the unique cells with data
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
cell.backgroundColor = [UIColor yellowColor];
UILabel *label = [[UILabel alloc] initWithFrame: cell.frame];
label.text = [self.array objectAtIndex: indexPath.row];
label.textColor = [UIColor blackColor];
[cell.contentView addSubview:label];
return cell;
}
To note: my array is of size 100 with randomly generated numbers.
Your help is appreciated :)
Thanks!
The array's frame should be related to the bounds of its cell, not its cell's frame, who's origin will grow as the indexPath grows. Also, we don't want to unconditionally create the labels, since the cells get reused. Only create a label if one doesn't exist....
UILabel *label = (UILabel *)[cell viewWithTag:99];
if (!label) {
label = [[UILabel alloc] initWithFrame: cell.bounds]; // note use bounds here - which we want to be zero based since we're in the coordinate system of the cell
label.tag = 99;
label.text = [self.array objectAtIndex: indexPath.row];
label.textColor = [UIColor blackColor];
[cell.contentView addSubview:label];
}
// unconditionally setup its text
NSNumber *number = self.myArrayOfRandomNumbers[indexPath.row];
label.text = [number description];

How to show a view created inside the custom tableview cell by swiping the row?

I have created the iPhone app which has the custom tableview cell and I also created a view in cellForRowAtIndexPath. Now, when i swiping the the cell in UITable the view that i created should be displayed in the particular cell and all other cell contents should be remained same.
My code as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
RKCardCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"RKCardCell"];
// Configure the cell...
if (cell == nil) {
cell = [[RKCardCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"RKCardCell"];
}
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeMethod:)];
swipeGesture.direction = UISwipeGestureRecognizerDirectionLeft;
[cell addGestureRecognizer:swipeGesture];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(-320.0, 8.0, 300, 180)];
[view setBackgroundColor:[UIColor greenColor]];
cell.profileImage.image = [UIImage imageNamed:[photoArray objectAtIndex:indexPath.row]];
cell.titleLabel.text = [titleArray objectAtIndex:indexPath.row];
cell.nameLabel.text = [nameArray objectAtIndex:indexPath.row];
cell.descriptionLabel.text = [descriptionArray objectAtIndex:indexPath.row];
//%%% I made the cards pseudo dynamic, so I'm asking the cards to change their frames depending on the height of the cell
cell.cardView.frame = CGRectMake(10, 5, 300, [((NSNumber*)[cardSizeArray objectAtIndex:indexPath.row])intValue]-10);
return cell;
}
Following code is for gesture swiping:
- (void)swipeMethod:(UIGestureRecognizer *)gestureRec
{
[UIView animateWithDuration: 0.5 animations:^{
CGRectOffset(self.rkCardCell.cardView.frame, -320.0, 0.0);
}];
}
Thanks in advance.
It is good if you use the gesture recognizer with the table view.
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeTarget:)];
swipeGesture.direction = UISwipeGestureRecognizerDirectionLeft;
[cell addGestureRecognizer:_myTableView];
And your swipe target method like as follows.
- (IBAction)swipeTarget:(UISwipeGestureRecognizer *)gestureRecognizer
{
CGPoint swipePoint = [gestureRecognizer locationInView:_myTableView];
NSIndexPath *cellIndexPath = [_myTableView indexPathForRowAtPoint:swipePoint];
RKCardCell *cell = [_myTableView cellForRowAtIndexPath:cellIndexPath];
// Add your code here to show your view
[UIView animateWithDuration: 0.5 animations:^{
CGRectOffset(cell.cardView.frame, -320.0, 0.0);
}];
}
Take a look on https://github.com/CEWendel/SWTableViewCell .
It's a really good and simple library to make custom swipable tableviewcell.

UICollectionView shows only the first item

I'm working on a project similar to a video album. In that I'm using UICollectionView to display the thumb images of those videos. The worst part is that I should not use storyboard or xib files. I have tried to do this programatically. I'm currently working on this code:
- (void)viewDidLoad
{
i = 0;
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
[layout setItemSize:CGSizeMake(self.view.frame.size.width/2.5,self.view.frame.size.width/2.5)];
collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
[collectionView setDataSource:self];
[collectionView setDelegate:self];
collectionView.backgroundColor = [UIColor whiteColor];
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"MyCell"];
[self.view addSubview:collectionView];
[super viewDidLoad];
}
I have given 1 for return in numberOfSectionsInCollectionView and [myArray count] for return in numberOfItemsInSection.
-(UICollectionViewCell *) collectionView:(UICollectionView *)cV cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [cV dequeueReusableCellWithReuseIdentifier:#"MyCell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor blackColor];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(cell.frame.origin.x , cell.frame.origin.y, cell.frame.size.width, (cell.frame.size.height - cell.frame.size.height/3))];
cell.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(cell.frame.origin.x , cell.frame.origin.y, cell.frame.size.width, (cell.frame.size.height - cell.frame.size.height/3))];
imageView.image = [UIImage imageNamed:[storeData objectAtIndex:i]];
[cell addSubview:imageView];
i++;
return cell;
}
I have rechecked the images in myArray. When the view loads, the collection view shows only the first image. Other 4 cells are empty. What is wrong with my code?
For those who is experiencing this problem, frame is the key. I've encountered this and changed:
cell.imageView.frame = cell.frame;
into
cell.imageView.frame = cell.bounds;
The op is using:
cell.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(cell.frame.origin.x , cell.frame.origin.y, cell.frame.size.width, (cell.frame.size.height - cell.frame.size.height/3))];
That's why this happened.
You shouldn't be using i as a counter. The whole point of the delegate method sending you an indexPath is that it tells you what information to get from your array of source data. So, remove i and use the indexPath.row instead.
You also don't need 2 image views. But you should probably keep your special subview and not use the cells built in image view.
You do not need a counter. As indicated by Wain, use indexPath.row.
Importantly, you should not create new subviews in cellForItemAtIndexPath, but rather use this method to fill them appropriately with content. You could put the image views into your storyboard prototype cells and identify them with tags. Each cell returned from dequeueReusableCellWithReuseIdentifier will already contain the image view.
you should never create ui elements in cellForRowAtIndexPath:. Subclass a collection view cell like so:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
NSLog(#"INIT WITH FRAME FOR CELL");
//we create the UIImageView here
imageView = [[UIImageView alloc] init];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.frame = CGRectMake(cell.frame.origin.x , cell.frame.origin.y, cell.frame.size.width, (cell.frame.size.height - cell.frame.size.height/3));
[self.contentView addSubview:imageView]; //the only place we want to do this addSubview: is here!
}
return self;
}
Then add that subclassed cell as a property and alter this code:]
[collectionView registerClass:[customCellClass class] forCellWithReuseIdentifier:#"MyCell"];
The perform these changes:
-(customCellClass *) collectionView:(UICollectionView *)cV cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = (customCellClass *)[cV dequeueReusableCellWithReuseIdentifier:#"MyCell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor blackColor];
imageView.image = [UIImage imageNamed:[storeData objectAtIndex:indexPath.row]];
return cell;
}
A final adjustment would be to move the the [super viewDidLoad] to this:
- (void)viewDidLoad
{
[super viewDidLoad];
//insert the rest of the code here rather than before viewDidLoad
}

Updating cells with UIImageView to show currently selected item

I am using a sliding view controller which holds the main controller on top and a slide left menu controller.
The controller on the left works as the menu like Facebook/Pintrest apps etc. It is a UITableView on the left.
Here is my setup:
cellForRowAtIndexPath
static NSString *CellIdentifier = #"MainMenuCell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UIView *topSplitterBar = [[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.bounds.size.width, 1)];
topSplitterBar.backgroundColor = [UIColor colorWithRed:62.0/255.0 green:69.0/255.0 blue:85.0/255.0 alpha:1];
[cell.contentView addSubview:topSplitterBar];
UIImage *arrowImage = [UIImage imageNamed:#"selectedArrow"];
self.arrowSelectedView = [[UIImageView alloc] initWithFrame:CGRectMake(240, 10, arrowImage.size.width, arrowImage.size.height)];
self.arrowSelectedView.image = arrowImage;
[cell.contentView addSubview:self.arrowSelectedView];
self.arrowSelectedView.hidden = YES;
}
//////
// ADDITIONAL GLUE CODE HERE TO SET LABELS ETC....
//////
if (currentDisplayed) {
// This is for the current item that is being displayed
cell.contentView.backgroundColor = [UIColor colorWithRed:50.0/255.0 green:56.0/255.0 blue:73.0/255.0 alpha:1];
self.arrowSelectedView.hidden = NO;
} else {
cell.contentView.backgroundColor = [UIColor colorWithRed:75.0/255.0 green:83.0/255.0 blue:102.0/255.0 alpha:1.0];
self.arrowSelectedView.hidden = YES;
}
NSLog(#"%#",cell.contentView.subviews);
return cell;
There are a total of 7 cells in 2 sections for the table view. One cell in section 1 (0) and the rest in section 2 (1). There are three cells which show a main controller on the top. Once they are selected I would like to update the table view to show an arrow next the cell like this:
Here is the example code for: didSelectRowAtIndexPath
UIViewController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ProfileVC"];
__weak typeof(self) weakSelf = self;
[self.slidingViewController anchorTopViewOffScreenTo:ECRight animations:nil onComplete:^{
CGRect frame = weakSelf.slidingViewController.topViewController.view.frame;
weakSelf.slidingViewController.topViewController = newTopViewController;
weakSelf.slidingViewController.topViewController.view.frame = frame;
[weakSelf.slidingViewController resetTopViewWithAnimations:nil onComplete:^{
NSIndexPath* displayNameRow = [NSIndexPath indexPathForRow:0 inSection:0];
NSIndexPath* gamesRow = [NSIndexPath indexPathForRow:0 inSection:1];
NSIndexPath* settingsRow = [NSIndexPath indexPathForRow:3 inSection:1];
NSArray* rowsToReload = [NSArray arrayWithObjects:displayNameRow, gamesRow, settingsRow, nil];
[weakSelf.tableView reloadRowsAtIndexPaths:rowsToReload withRowAnimation:UITableViewRowAnimationNone];
}];
}];
Issue/Question
So I have a strange issue here, were if I click on a different cell it works the arrow is shown on the other cell. Then again this works for 2 more times, then the third times it randomly decides to show the uiimageview on another cell.
Even if I step through the cell creation process I see for that specific cell (the incorrectly displayed one) the boolean for currentDisplayed is set to NO, so it doesn't change the arrowSelectedView to not hidden yet it does somehow? I log out the subviews and can see that it is randomly not Hidden anymore even though for that specific cell it is not set to not hidden, so I am thinking this is implemented incorrectly somehow?
The main issue here is that in -tableView:cellForRowAtIndexPath: you're creating a new image view every time you create a new cell, then storing it into a single ivar. The call to set or hide the image view later in that method is not guaranteed (indeed is actually quite unlikely) to be addressing the same image view that was added into that particular cell's content view.
A more convenient place to store it would be in a subclass of UITableViewCell's view like so:
#interface CustomTableViewCell : UITableViewCell
#property (strong, readwrite) UIImageView *imageAccessory;
#end
#implementation CustomTableViewCell
#end
#implementation YourClass
- (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MainMenuCell";
CustomTableViewCell *cell = (CustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (nil == cell) {
cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UIView *topSplitterBar = [[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.bounds.size.width, 1)];
topSplitterBar.backgroundColor = [UIColor colorWithRed:62.0/255.0 green:69.0/255.0 blue:85.0/255.0 alpha:1];
[cell.contentView addSubview:topSplitterBar];
UIImage *arrowImage = [UIImage imageNamed:#"selectedArrow"];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(240, 10, arrowImage.size.width, arrowImage.size.height)];
imageView.image = arrowImage;
cell.accessoryImage = imageView;
[cell.contentView addSubview: cell.accessoryImage];
cell.accessoryView.hidden = YES;
}
if (currentDisplayed) {
// This is for the current item that is being displayed
cell.contentView.backgroundColor = [UIColor colorWithRed:50.0/255.0 green:56.0/255.0 blue:73.0/255.0 alpha:1];
cell.accessoryImage.hidden = NO;
} else {
cell.contentView.backgroundColor = [UIColor colorWithRed:75.0/255.0 green:83.0/255.0 blue:102.0/255.0 alpha:1.0];
cell.accessoryImage.hidden = YES;
}
return cell;
}
#end

Button in UITableview modify current cell custom

I not find a solution to modify my custom cell since a button which is inside. I will wish to change the label text when I click the button.
- (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:nil];
}
// View
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 250)];
[view setBackgroundColor:[UIColor colorWithWhite:255.0 alpha:0.0]];
// Label
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320-7-7, 16)];
[label setText:#"Hello"];
[label setTextAlignment:UITextAlignmentLeft];
[label setTextColor:[UIColor grayColor]];
[label setFont:[UIFont fontWithName:#"HelveticaNeue-Bold" size:16]];
[label setBackgroundColor:[UIColor clearColor]];
[view addSubview:label];
// Action
UIButton *action = [[UIButton alloc] initWithFrame:CGRectMake(306-54, 0, 54, 54)];
[action setTitle:#"0" forState:UIControlStateNormal];
[action addTarget:self action:#selector(actionMore:) forControlEvents:UIControlEventTouchUpInside];
[view addSubview:action];
// Add view to cell
[cell addSubview:view];
return cell;
}
Edit (add details)
- (void)actionMore:(id)sender{
UIButton *button = (UIButton *)sender;
// Edit current cell, but I do not know how...
}
Thanks.
You can get the cell in which the button was pressed with following lines of code
UITableViewCell * cell = (UITableViewCell*)[[sender superview] superview];
Then use the cell reference to change the label text
cell.yourlabel.text = #"New Text";
Update
I think the above code may not work in iOS 7. The better way is
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.mainTable];
NSIndexPath *indexPath = [self.mainTable indexPathForRowAtPoint:buttonPosition];
Since your UIButton and UILabel are subviews of the same view, you can tag your label, and use viewWithTag to find it from your button's action code:
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320-7-7, 16)];
label.tag = 1234;
....
- (void)actionMore:(id)sender{
UIButton *button = (UIButton *)sender;
UILabel *label = [[sender superview] viewWithTag:1234];
// Edit current cell
}
To help you need to give some more details.
Is this a single cell or is it a prototype for multiple?
The code in the actionMore: selector.
What are you trying to do this for? Why a button in a cell to change the label text?
If this cell is being used more than once, a problem could be actionMore: can't isolate which cell is the target for the code. Also you could have a simple typo in the actionMore method but we can't solve that without being able to see all of the interacting code.
If you can provide more details, some one may be able to help. I will edit this answer if I can help you once I have more information.
--EDIT--
First to get cell you can use:
UITableViewCell * cell = (UITableViewCell*)[[sender superview] superview];
Then you can access your cells label by:
cell.label.text = #"Some Text Here";
Your next issue is figuring out where in the list your cell lies. For that use this code:
UITableView * table = (UITableView*)[[[sender superview] superview] superview];
NSIndexPath * indexPath = [table indexPathForCell: cell];
You then can then use a switch statement or if-else statements to find which row was triggered.
- (void)actionMore:(id)sender{
UITableViewCell * cell = (UITableViewCell*)[[sender superview] superview];
UIView *view = [cell.subviews objectAtIndex:0];
UILabel *label = [view.subviews objectAtIndex:0];
[label setText:#"test"];
}
you better add view as a subview of the contentview
pass the indexpath to actionMore or fetch it from there. once you got the indexpath, you are in business.
you may want to set a tag for your textlabel for fetching it from its superview.

Resources