I have a uicollectionView inside a tableview cell. I am trying to figure out to have unique data source for each collectionview based on the index of the tableViewCell. Here is what I have so far... How do you get each cell to have different collectionview data source?
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"collectionViewCell" forIndexPath:indexPath];
UILabel *title = (UILabel* )[cell viewWithTag:100];
title.text = [collection1 objectAtIndex:indexPath.row];
// Configure the cell
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"tableViewCell" forIndexPath:indexPath];
// Configure the cell...
return cell;
}
This should set you on the right track:
Your data source for your UITableView should be a collection of data sources for each cell and hence each UICollectionView. So for example, say you want to show some images in each of your UICollectionViewCells. In this scenario, the data source for your UITableView could be an Array containing Arrays of images (one Array of images for each cell in your UITableView).
You will need a custom UITableViewCell that exposes a method like "SetDataSourceForCollectionView".
Then in the cellForRowAtIndexPath method of the UITableView you can get the data source for the cell by indexing your collection using the NSIndexPath parameter. Just pass this value to the SetDataSourceForCollectionViewmethod of your UITableViewCell.
Your custom UITableViewCell now has a datasource it can assign to it's UICollectionView.
Related
I've got a table view and this method to find the indexPath of a subview of one of its cells...
- (NSIndexPath *)indexPathContainingView:(UIView *)view {
while (view && ![view isKindOfClass:[UITableViewCell self]]) {
view = view.superview;
}
UITableViewCell *cell = (UITableViewCell *)view;
return (cell)? [self.tableView indexPathForCell:cell] : nil;
}
I call with a subview of the topmost cell (which is visible, the table view has not been scrolled), and, with a breakpoint on the return line, I get this perplexing result in lldb...
cell looks good. The cell's table view matches my tableView (there's some intermediate UITableViewWrapperView as the direct superview). But see how indexPathForCell: returns nil? I am certain that the cell is visible.
I don't think it matters, but the subview of the cell I begin with is a UICollectionView, and I'm calling this on the collection view's datasource methods.
Any ideas?
EDIT more context...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
// do stuff to setup the cell
// now reload the collection view that it contains
UICollectionView *collectionView = (UICollectionView *)[cell viewWithTag:33];
[collectionView reloadData];
return cell;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
NSIndexPath *indexPath = [self indexPathContainingView:collectionView];
return // get my model from the index path and return the count of an array it contains
// but here's the problem. index path is nil here
}
Assuming you are using storyboards and if you are willing to change the approach you are using a possible solution would be (And a cleaner solution in my opinion):
Drag an outlet of your UICollectionView inside your cell into the UITableViewCell. In your storyboard again set the delegate and dataSource of the UICollectionView to your class by dragging the outlet. Of course you will have to use a custom UITableViewCell
In your cellForRowAtIndexPath for the UITableView set the tag of the the UICollectionView to be your indexPath.row. Now in your numberOfItemsInSection you can access the UICollectionView tag property and it will contain the indexPath.row of the UITableViewCell you are trying to access and hence you can access your model.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
// do stuff to setup the cell
// now reload the collection view that it contains
cell.collectionView.tag = indexPath.row;
[cell.collectionView reloadData];
return cell;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
// get my model from the index path and return the count of an array it contains
Model *model = dataArray[collectionView.tag];
return model.count;
}
I'm using Two tableview cells on single tableview like dis...enter image description here
and when I put subviews on both cells it is showing Outlets cannot connected to repeating content in uitableview
You can access the views with the help "tag". First set tag to the required view then access it as follows,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"tCell"];
//I have set CollectionView tag to 100 and Label tag to 50
UICollectionView *collect = (UICollectionView *) [cell viewWithTag:100]; //if the view is CollectionView
UILabel *lbl = (UILabel *) [cell viewWithTag:50]; //if it is a UILabel
return cell;
}
I have this little doubt about reusing UITableViewCell.
When we create UITableViewCell it kinda looks like following.
- (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];
[self configureCell:cell forIndexPath:indexPath];
}
}
- (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {/**Cell Config Code Goes Here**/}
}
So in my case, every cell in UITableView is different. And if UITableView reuses the cell the cell content is completely different.
Is it good practice to just pass CellIdentifier as nil so every time new cell is created instead given the condition that all cells are different ?
Or should I just move [self configureCell:cell forIndexPath:indexPath]; out and handle it on by my own ?
Cell reusability has its sense if you are using cell contents(same subviews) multiple time. Like you have two lables in your tableViewcell for all rows in your tableView. If you have small number of different cells. like if you have three types of cells to use multiple times in your tableView, you can use cell reusability with 3 different cell identifier.
But if you have all different cell, then its fine if you skip cell reusability.
The proper way of using reusability of the tableView is shown below.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"FollowerCell";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell =[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
[self configureCell:cell forIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {/**Cell Config Code Goes Here**/}
}
The basic idea of reusability is that every time the similar type of cell should not be created, instead they should be reused just by updating their content.
What happens behind the scene is that there is a queue created in which these similar cells are added. Now Suppose there are 200 rows with different data but only 10 rows are visible. That in the queue only approx 14 cells will be present. Now as you will scroll the tableview up or down, this condition
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
checks wether the queue contains any cell, if yes a cell is fetched from the queue. Also the cells, which were earlier visible now on disappearing are added into the queue. This way everytime instead of new cells are created, the already created cells are used.
Now if you forcely make the cell = nil, than every time new cells will be created and added in the queue. Now if there are 200 data than queue will be containing 200 cells thus resulting in increase in memory size.
Hope it will help you in understanding the tableView. Happy Coding :)
I am afraid you have to move the configure cell code out of if condition to make every cell has its own content.
- (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];
}
[self configureCell:cell forIndexPath:indexPath];
}
While we saying reuse of UITableViewCells, we mean that we don't have to create the UIView hierarchy inside the cell every time. But you need to configure the content for different cells. Like cell.titleLabel.text = xxxx.
Meanwhile, you can use multiple reuseIdentifiers for different kind of cells. Or if you only have one such cell, you can define a cell as an attribute instance so that you don't have to create it everytime.
I've created a UITableView in my application. I've Created a custom UITableViewCell called VideoCell which contains a UIWebview, a UIImageView and a UILabel.
The UIWebView is the same size as the UIImageView and in the same location, but behind the UIImageView. I want to hide the UILabel and the UIIMageView when I tap the cell, so that the UIWebView is revealed.
The VideoCell has a ReuseIdentifier set in the storyboard editor which I use for dequeing the VideoCell from in tableView:cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"VideoCell";
VideoCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
...
return cell;
}
How can I get a reference to the actual cell that I tap in tableView:didSelectRowAtIndexPath: in order to visibly change the properties?
I've tried just dequing with the same arguments
VideoCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Which returns me a VideoCell, but with no fields set up
I've also tried calling tableView:cellForRowAtIndexPath:
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
but that returns me a new instance of the VideoCell with the correct fields set up, and this is not the one that is currently displayed.
VideoCell *cell = (VideoCell*)[tableView cellForRowAtIndexPath:indexPath];
Don't call the data source method present in ViewController, call the method on actual instance of your UITableView
Try using this
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
instead of
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
cellForRowAtIndexPath:
is the correct way to get the instance of the cell. If you are unable to retrieve the exact cell you want in this way, it just means that your implementation in that method is wrong.
I'm trying to display a UITableView with a list of artists who read from Last.fm API. I store all the artists in an array, then I show a table with your name and your picture.
Initially the photos look good, but when I do scroll the images are very small.
This is the initial appearance:
This is the appearance after scrolling, with the problem:
This is my code for create the cells:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TopArtistCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
JSCArtist *artist = self.artists[indexPath.row];
cell.textLabel.text = [artist name];
[cell.imageView setImageWithURL:[NSURL URLWithString:[[artist photo] thumbnail]] placeholderImage: [UIImage imageNamed:#"default_photo.jpeg"]];
return cell;
}
The default imageView for a UITableView acts a little odd. I would just create a custom UITableViewCell subclass and do your own layout.