I am trying to work with UICollectionView that is a part of the UITableViewCell.
So the issue I faced, the collection view for visible table cells works ok, but when I start scroll table and table starts create new cells that where invisible then I faces with some behaviour that duplicate first table cell. For example I have scrolled collection view in first table view cell, then I scrolled table view down, and what I see the new cell have the same state as my first cell had. You can check source here repo and the video here to understand what I am talking about.
Have a property of UICollectionView in CustomTableViewCell.h and bind it in Main.storyboard. Let's assume declared it like this:
#property (strong, nonatomic) UICollectionView *collectionView;
In ViewController.m change cellForRowAtIndexPath method, so it reloads inside UICollectionView every time it need
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CustomTableViewCell"];
[cell.collectionView reloadData];
[cell.collectionView scrollRectToVisible:CGRectZero animated:NO];
return cell;
}
Of course, you need to import CustomTableViewCell.h on ViewController.m file.
-[UITableViewCell prepareForReuse]
Problem with reuse identifier in UITableView cell, if you use single cell identifier in cellForRowAtIndexPath this problem will occurs
1. Use Dynamic cell identifier for each row, like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[NSString stringWithFormat:#"CustomTableViewCell_%d",indexPath.row]];
}
2.Store content offset for each collection view in array, and reset collection view content offset
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
......
[cell.collectionView setContentOffset:scrollingPoint animated:NO];
return cell;
}
Related
I haven't developed any iOS apps in a while. I am fine with both swift and Objective-C but what I find different is adding a UITableView to ViewController. Before, I used to add a UITableView to ViewController, add the required datasource methods and the typical UITableViewCell object, and return the cell in cellForRowAtIndexPath:, which would display empty cells depending on the number of rows I return. Now, I did everything the same, but the UITableView is empty and when I scroll I see the lines but not my cell.textlabel.text value, which I set. It seems now I am supposed to add UITableViewCell to the UITableView and remove the
#pragma-mark TableView Datasource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_formTitles count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:#"cell"];
if(cell==NULL)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"cell"];
}
cell.textLabel.text=[_formTitles objectAtIndex:indexPath.row];
cell.detailTextLabel.text=#"Kaushik";
return cell;
}
I can't find a simple post online regarding the same.
Can someone post what are the changes in the new iOS 9 in a simple manner?
Thank you
Right..For those of you who are still prefer to add a tableview to a viewcontroller.Here are the steps
In the ViewController drag and drop the tableview.Now instead of the lines which you see in the old Xcode.This time you would see a blank table view with the text " Table View prototype content" in the middle.
We usually create a tableviewcell only we doing anything different like adding more labels or image etc but hereafter it is required to add a tableviewcell in the tableview.Drag and drop a tableview onto the tableview.It will display as protype cells.One can select type of cell here itself as basic,value 1,value 2 or subtitle.Also NEED TO SET THE REUSE IDENTIFIER IN THE STORYBOARD UTILITIES PANEL ON YOUR RIGHT. At the end, you can select the tableview and add the missing constraints.
Implement the typical required datasource methods in your viewcontroller class.
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:#"cell"];
cell.textLabel.text=#"text";
cell.detailTextLabel.text=#"DetailedText";
return cell;
}
The change here is that we dont require the usual if(cell==nil)
{..}
piece of code since we added the prototype cells to the storyboard.
Don;t forget to connect the delegate and datasource of the tableview to the viewcontroller.
This should display the tableview in your viewcontroller but i am getting a space on top of the tableview which i don't know why.Anyway this is how you add a tableview to a view controller using Objective-C language in iOS 9.3.
FYI: Guys if i've missed anything, please mention it in the comments
Thank you
Put tableView to view controller and link it to viewcontroller.
link delegate and datasource of tableview to viewcontroller.
in
viewcontroller.h
#interface ViewController :<UITableViewDelegate, UITableViewDataSource>
in viewWillAppear put
tblService.delegate=self;
tblService.dataSource=self;
and your array elements.
5.Impliment your tableview delegate method and datasource method .
6.be sure you cell identifier equal the one put on storyboard.
this link will help you more to implement your first app and this video.
I want a tableview inside another tableviewCell like the following image.It shows one complete cell with a few details and a tableview. How can i do this?I was following this link Link.This is an old code .It is using xibs.I dont have any idea where to set the delegate for the inner tableview.Please help.Any suggestion will be realy helpfull.
My first idea would be:
Subclass UITableViewCell ("MainTableViewCell") and extend it with UITableViewDelegate and UITableViewDatasource.
Next to all the properties you need in "MainTableViewCell" add a TableView "tableViewFilms" and an array "films" for the Films. Also don't forget to add the datasource methods for a tableview to the implementation file.
To easily setup a cell I add a setup-method to the header-file. Which can be called once the cell is instantiated. You can modify it as you want, give it as many parameters as you want and in the implementation (see step 4) set datasource and delegate of your inner tableview.
- (void)setupCellWithDictionary:(NSDictionary *)dict AndArray:(NSArray *)filmsForInnerTable;
You can call this method in your datasource method, once a cell is instantiated:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MainTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainTableViewCell" forIndexPath:indexPath];
NSDictionary *dict = (NSDictionary *) allDataDictionaries[indexPath.row];
[cell setupCellWithDictionary:dict AndArray:filmsForInnerTable];
return cell;
}
Subclass UITableViewCell another time: "FilmTableViewCell"
When setting up the a Cell of "MainTableViewCell", set the delegate and the datasource of "tableViewFilms" to self (object of "MainTableViewCell").
- (void)setupCellWithDictionary:(NSDictionary *)dict AndArray:(NSArray *)filmsForInnerTable{
self.films = filmsForInnerTable;
self.tableViewFilms.dataSource = self;
self.tableViewFilms.delegate = self;
[self.tableView reload];
//more instructions
}
Populate the tableview with the data from the array "films" using "FilmTableViewCells".
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
FilmTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"FilmTableViewCell" forIndexPath:indexPath];
Film *film = (Film*)films[indexPath.row];
[cell setupCellWithFilm:film];
return cell;
}
Hope this helps.
Don't forget to use Outlets, the method definitions and to set the reuse-identifiers for the cells!
Check my answer in this ios 8 Swift - TableView with embedded CollectionView. You have replace that UICollectionView with UITableView.
Everything else is pretty much the same. Its just a head start with UITableView and UICollectionView created programmatically.
I can change it accordingly if you don't understand.
I have gif animated pictures in some uitableview rows,
When there is a lot of gifs in tableview CPU usage is going to be very high,
So I want to hide these gifs when their row is not visible,
How can I do that ?
How can I achieve not visible cells row's indexPath ?
After that I can hide the gif like that :
UITableViewCell *celll = [ tableView cellForRowAtIndexPath:indexPath];
UIImageView *gif = (UIImageView*)[celll viewWithTag:30000];
gif.hidden = TRUE;
So I must get not visible cells indexPath's in a loop.
Generally, you don't need to do that as long as you properly use reusable cells.
Nevertheless, if you do want to do that, you can use tableView:didEndDisplayingCell:forRowAtIndexPath: method on UITableViewDelegate:
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath {
UIImageView *gif = (UIImageView*)[celll viewWithTag:30000];
gif.hidden = YES;
}
If you'll put the line:
NSLog(#"%#",indexPath);
as the first line of the method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
You'll realise that it's done automatically. Only the visible cells, i.e the one that appears on the screen, are the one you present the data for.
Sorry for poor english.You had not posted code about how your cellForRowAtIndexPath implementation look like,i will suggest to make your cellForRowAtIndexPath like below.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"YOURIDENTIFIERSTRING";
UITableViewCell *cell = [tableView dequeReusableCellWithIdentifier: CellIdentifier forIndexPath:indexPath];
// Configure the cell here …
return cell;
}
This way only those many cells will be created which are visible on device and once row goes out of device view it will be reuse for new row. Please check apple doc for tableview.
I would like to have a UITableView with a UIWebView in each cell. The UIWebView should have the contentSize so that it shows its whole content without scrolling. My problem is the HeightForRowAtIndexPath because the content has to be loaded first before it can return a value.
I did something like this in this old and maybe no more up-to-date code:
https://github.com/Daij-Djan/DDUtils/tree/master/ui/M42WebviewTableViewCell%20%5Bios%5D
Disclaimer: My own open source code
How it works:
In the dataSource:
you return the cell's preferredHeight (which is 0 if there is no content)
you also implement the delegate - (void)tableCellDidLoadContent:(M42WebviewTableViewCell*)cell;
you reload your table which will invalidate all Heights. When you now return preferredHeight it is valid and the views appear alright.
I would subclass UITableViewCell in this (very MVC) way:
#interface CustomTableViewCell : UITableViewCell
#property (nonatomic,strong) id model;
+(CGFloat)heightForModel:(id)model;
#end
Model can be whatever your want. This is a very generic example.
In heightForModel you calculate the exact height of the cell.
In the init method of CustomTableViewCell, you should add a blank UIWebView to the cell.
When you "set" model property, you should refresh cell UI.
Then in the class that implements the delegate methods (assuming that cell models are stored in a NSArray called models):
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [CustomTableViewCell heightForModel:self.models[indexPath.row]];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([CustomTableViewCell class])];
cell.model = self.models[indexPath.row];
return cell;
}
Remember to register your custom cell!
I need to have a custom cell height for all of my cells in my UITableView. In this method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
I try this:
if ([[tableView cellForRowAtIndexPath:indexPath] reuseIdentifier] == #"imageCell")
As I have 3 different cells setup with different identifiers in my storyboard. However my app just crashes here with EXC_BAD_ACCESS.
Any idea why?
Thanks.
You're comparing a string, so you should be using isEqualToString:
if ([[[tableView cellForRowAtIndexPath:indexPath] reuseIdentifier] isEqualToString:#"imageCell"])
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
you are supposed to calculate the height for you row, not to get the Cell of your tableView.
In my opinion, in the lifeCycle of a TableView delegate, the 1st step (before allocating each UITableViewCell), the TableView delegate call heightForRowAtIndexPath for each row (but at this moment, the UItableViewCell are not allocated). The, in a 2nd step, the TableView call
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
to create UitableView Cells.