I'm trying to get a UITableView to work with Core Data using an NSFetchedResultsController, while also having an insertion control (UITableViewCellStyleInsert) as the last row during editing.
Since the insertion control is just another tableviewcell, just with a different editing style, I have changed the appropriate UITableViewDatasource delegate methods, like:
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self isInsertionControl:indexPath]) {
return UITableViewCellEditingStyleInsert;
} else {
return UITableViewCellEditingStyleDelete;
}
}
The reported number of rows should also be updated accordingly, when editing (assuming there's only one section for now):
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id<NSFetchedResultsSectionInfo> sectionInfo = self.fetchedResultsController.sections[section];
NSUInteger numberOfObjects = sectionInfo.numberOfObjects;
// FIXME, things will go out of hand with more than one section.
if (self.tableView.editing) {
return numberOfObjects + 1;
} else {
return numberOfObjects;
}
}
And if requested, return the appropriate cell for the insertion row:
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *tableViewCell = nil;
if ([self isInsertionControl:indexPath]) {
static NSString *InsertIdentifier = #"InsertCell";
tableViewCell = [tableView dequeueReusableCellWithIdentifier:InsertIdentifier
forIndexPath:indexPath];
} else {
tableViewCell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier
forIndexPath:indexPath];
[self configureCell:tableViewCell atIndexPath:indexPath];
}
return tableViewCell;
}
This doesn't work, can anybody help me find out why?
QUICK EDIT
To be clear, I have 2 prototype cells in my storyboard, one for the regular content and one for representing the insertion row, both with the appropriate reuse identifier.
Related
I have a UITableViewController that I'm building up in my application. This UITableViewController (SelectedLanguages) is called from another UITableViewController (ChooseLanguage) where there is a static list of languages for the user to select.
In the SelectedLanguages UITableViewController, I want to achieve the following:
2 Sections
The first section will have between 1 and 5 cells
The second section will always have 12 cells.
The number of cells in the first section is entirely dependent on which language the user chooses in the ChooseLanguage UITableViewController. For example, clicking on English will mean the first section in the SelectedLanguage UITableViewController will have 5 cells, but choosing French in the ChooseLanguage UITableViewController will mean the first section in the SelectedLanguage will only have 1 cell.
As mentioned, the second section will always have 12 cells in the SelectedLanguage.
I have designed this UITableViewController in Interface Builder. What I've seen is that only if the the Content is specified as Static Cells can you have multiple "sections".
Even if you set the Content to Dynamic and Grouped, I can't seem to find a way to determine sections other than in code.
The reason I'm defining this in Interface Builder is because section 1 and section 2 will need to have a very customised layout of the size of the cells, as well as the labels that go into each cell.
The content of the first section is not dynamic; it is static because while building this application, I'll know exactly how many cells there should be in the first section for each language, so in my head, it is correct to use a Static cell.
My question is, how can I achieve setting the number of cells in the top section, in code?
In the prepareForSegue of the ChooseLanguage, I could check the called cell title and then perform some action in the SelectedTransactions. The action to perform here is what I'm confused about.
I know there's the method - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section in the UITableView Data Source, but I'm not sure how and what to do with this with my particular situation.
Any guidance would be really appreciated.
My easiest answer for your question is below
in .m
import "ViewController.h"
#interface ViewController ()
{
NSMutableArray *arraysection1;
NSMutableArray *arraysection2;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
arraySection1 = [[NSMutableArray alloc]initWithObjects:#"One",#"Two",#"Three",#"Four",#"Five",nil];
arraySection2 = [[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3",#"4",#"5",nil];
}
#UITableView Delegate Methods
#UITableView DataSource Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//If you have 2 sections,
return 2;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//set row of two sections with condition
if(section==0)
{
return arraySection1.count;
}
else
{
return arraySection2.count;
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *strCellIdentifier = #"CellIndentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:strCellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strCellIdentifier];
}
if(indexPath.section==0)
{
cell.textLabel.text = [NSString stringWithFormat:#"%#",[arraySection1 objectAtIndex:indexPath.row]];
NSLog(#"The textLabel is-%#",cell.textLabel.text);
}
else
{
cell.textLabel.text = [NSString stringWithFormat:#"%#",[arraySection2 objectAtIndex:indexPath.row]];
NSLog(#"The textLabel is-%#",cell.textLabel.text);
}
return cell;
}
#UITableView Delegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.section==0)
{
if(indexPath.row==0)
{
//Do whatever you want here
}
else if(indexPath.row==1)
{
//Do whatever you want here
}
else if(indexPath.row==2)
{
//Do whatever you want here
}
else if(indexPath.row==3)
{
//Do whatever you want here
}
else
{
//Do whatever you want here
}
}
else
{
if(indexPath.row==0)
{
//Do whatever you want here
}
else if(indexPath.row==1)
{
//Do whatever you want here
}
else if(indexPath.row==2)
{
//Do whatever you want here
}
else if(indexPath.row==3)
{
//Do whatever you want here
}
else
{
//Do whatever you want here
}
}
}
From what you are describing it sounds like your tableView should be dynamic.
You will have to handle this programmatically, forget about interface builder
Here is what you need:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;//2 Sections
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
switch (section) {
case 0:
//The first section will have between 1 and 5 cells
//Put the logic to return the correct number of cells
return 5;
break;
case 1:
//The second section will always have 12 cells.
return 12;
break;
default:
break;
}
return 0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
switch (indexPath.section) {
case 0:
[[cell textLabel] setText:#"same title section 1"];
break;
case 1:
[[cell textLabel] setText:#"same title section 2"];
break;
default:
break;
}
return cell;
}
How to work in two UITableView in a single View Controller in ios.In my app i designed the textfield and the buttons in a tableview(FirstTableVie).And i try to implement the comboBox in one of the textfield.Here the i implement the delegate function for comboBox tableview(SecondTableView), while i run this it shows the SecondTableView the FirstTableView is not displaying.So hlep me to implement the two bale view in a single ViewController.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if(tableView==self.FirstTableView)
{
return 0;
}
else if(tableView==self.SecondTableView){
return [stateArray count];
}
return 0;
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell;
if(tableView==self.FirstTableView)
{
}
else if(tableView==self.SecondTableView)
{
static NSString *identifier=#"Cell";
cell=[tableView dequeueReusableCellWithIdentifier:identifier];
if(cell==nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
cell.textLabel.text=[stateArray objectAtIndex:indexPath.row];
}
return cell;
}
You can check like below.I wrote only the conditions not entire code..
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if(tableView==self.FirstTableView)
{
return 0;
}
else if(tableView==self.SecondTableView){
return [stateArray count];
}
return 0;
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell;
static NSString *identifier=#"Cell";
cell=[tableView dequeueReusableCellWithIdentifier:identifier];
if(cell==nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
if(tableView==self.FirstTableView)
{
}
else if(tableView==self.SecondTableView)
{
cell.textLabel.text=[stateArray objectAtIndex:indexPath.row];
}
return cell;
}
Hope it helps you..
Maybe just create custom class/objects that you set the delegate methods to let them own it and implment the delegate methods in your custom classes.
i.e.
#interface TableViewHandler : NSObject
#end
#implmentation
// implement delegate methods
#end
then initialize and allocate these objects and assign them to the delegates of your two table views.
so in your view controller you can do
tableViewHandler *one = [[TableViewHandler alloc] init]; // you can implment an init if you want otherwise it goes to the NSObject init
and then assign the delegate methods of your first table view to this object.
so instead of the typical in a viewController
myTableview.delegate = self
you would do
myTableView.delegate = self.one;
and of course dataSource as well.
The advantage of this over if this table view or that is you can segregate the code.
It depends if you want re-usability of code. There is less re-usability in ViewControllers that are structured with if this class or that or that. Custom classes can be cleanly modified and carried around to other projects as needed. For example if you want to use one of these tables in another project you'd be messing around with copying and paste from the all the delegate methods you add the if else logic to. If you isolate the code you can just port the file.
Add tags to two tableview and check the if the condition while handling in the
table view delegate like
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section ;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if(tableView.tag==1) {
} else {
}
}
I just posted the logic how to approach
Actually I don't see a problem here. Every delegate and dataSource protocol method returns a refernce to a prticular TableView. Just set you view controller as a delegate to both tables and find out which of two is used in callback. You can distinguish tables by tag.
Example:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView.tag == 1) {
return 5;
}else if (tableView.tag == 2){
return 10;
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
if (tableView.tag == 1) {
cell = [self configreCellForFirstTableAtIndexPath:indexPath];
}else if (tableView.tag == 2){
cell = [self configreCellForSecondTableAtIndexPath:indexPath];
}
return cell;
}
I have a one View controller managing 2 tableviews. I use a flag to track which table is selected. In each of the delegate functions I just check the flag and use the right table.
Everything works great except that when i load the second table which has lesser items than the first one, crashes when I scroll the table , for the following error.
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no object at index 2 in section at index 0'
* First throw call stack:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Drawing Row = %d Total num Of items = %d", indexPath.row, [[self.fetchedResultsControllerComments fetchedObjects] count]);
Prints this:
Drawing Row = 2 Total num Of items = 0
If the number of items in this table is correct, then why is this function getting called in the first place?
Here is the code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(currentSelectionTableType1)
{
// Draw first kind of cell.
PlainImageCell *cell1 = [tableView dequeueReusableCellWithIdentifier:#"ImageCell"];
if(cell1 == nil)
cell1 =[[PlainImageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"ImageCell"];
[self configureCell1:cell1 atIndexPath:indexPath];
return cell1;
}
// else Draw the second kind of cell
PlainTextCell *cell2 = [tableView dequeueReusableCellWithIdentifier:#"TextCell"];
if(cell2 == nil)
cell2 =[[PlainTextCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"TextCell"];
[self configureCell2:cell2 atIndexPath:indexPath];
return cell2;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if(currentSelectionTableType1)
return [[self.fetchedResultsControllerDataSource1 sections] count];
return [[self.fetchedResultsControllerDataSource2 sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo;
if(currentSelectionTableType1)
{
sectionInfo = [self.fetchedResultsControllerDataSource1 sections][section];
}
else
{
sectionInfo = [self.fetchedResultsControllerDatasource2 sections][section];
}
return [sectionInfo numberOfObjects];
}
Thx
EDIT - based on the code you added:
You need to define one cell before your conditional and then configure that cell based on the conditional and then return the cell after the conditional. If you need both an ImageView and a TextCell, you can configure those objects in the conditional code.
Why not just use one TableView with two datasources and switch out the datasources as needed?
Something like this:
#property(nonatomic, strong) NSArray *tableViewDataSource1;
#property(nonatomic, strong) NSArray * tableViewDataSource2;
#property(nonatomic) BOOL usingDataSource2;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (self.usingDataSource2) {
return [self.tableViewDataSource2 count];
}
return [self. tableViewDataSource1 count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Create the cell before conditional
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"reuseIdentifier" forIndexPath:indexPath];
// Conditionally configure the cell
if (self.usingDataSource2) {
// Configure Cell using self.tableViewDataSource2 data
} else {
// Configure Cell using self.tableViewDataSource1 data
}
// Return the configured cell after the conditional
return cell;
}
I have managed to make the TableView expandable. The problem is that when I start the app, it's always opened. I want it to be closed, and to be opened just when I hit the row.
What am I missing here? How can I set it to be open at start?
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (!indexPath.row)
{
// first row
cell.textLabel.text = #"Expandable"; // only top row showing
}
else
{
cell.textLabel.text = #"Some Detail";
cell.accessoryView = nil;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section
{
return YES;
}
You first create a regular table with some array of booleans that holds the state of each row (open/close).
Then, when you hit a first row in a section, I reload the table with new rows:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//subject hitted
if (indexPath.row == 0)
{
// set relevant boolean here ,also , reload the table again with the new rows
collapsedRows[indexPath.section]= ! collapsedRows[indexPath.section];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section]withRowAnimation:UITableViewRowAnimationFade];
}
//sub subject hitted
else
{
}
}
I'm looking for the best possible solution for a complex UITableView. What I want : I have an arbitrary number of sections. In this section is just one static cell and then should come any number of dynamic cells.
My Data are stored in some NSMutableArray and i tried somethink like this:
Combine static and prototype content in a table view
But i dont know how to handle it with my kind of problem.
So can somebody give me a hint or a best practice?
UPDATE: 1
http://jsfiddle.net/konstheinrich188/HKkA8/ Fiddle shows how my data looks and what im trying todo
This pic shows how i want to code my tableview...
When you are using the term "static", are you really talking about a "uitableview static cell", or rather "cell with static content"?
If the former; why do you need that?
If the latter; how about testing in each section whether this is the first cell in the section, and then presenting static content? For all other cells, display dynamic content:
if (indexPath.row == 0) {
// First row in section. Display static content
...
} else {
// Display dynamic content
...
}
For what purpose do you need the static cells?
So after a while and some testing and listen to your ideas and technicals i solved my problem!
Here is a little code :
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [mappedSprints count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
UISprint*s = [mappedSprints objectAtIndex:section];
return s._name;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
UISprint* s = [mappedSprints objectAtIndex:section];
return [s.internalUserStorey count] + [s.externalUserStorey count] + 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0) {
return 130;
}
return 80;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[NSString stringWithFormat:#"Cell%d%d", indexPath.row, indexPath.section]];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[NSString stringWithFormat:#"Cell%d%d", indexPath.row, indexPath.section]];
}
UISprint*s = [mappedSprints objectAtIndex:indexPath.section];
if (indexPath.row == 0) {
//Here is my first cell
//cell.textLabel.text =s._name;
}
else if(indexPath.row >= 0 && indexPath.row<=[s.internalUserStorey count]){
//here are the cells for SubItem
}
else if(indexPath.row >= [s.internalUserStorey count]){
//here are the cells for SubItem 2
}
return cell;
So thanks to all !!
Best Konstantin
You can take one NSMuatableArray and add references on that i.e.
NSMuatableArray *arr=[NSMuatableArray alloc]init];
//section no 1
[arr addObject:#"2"];
//section no 2
[arr addObject:#"1"];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
switch(arr objectAtIndex[indexPath.row])
{
}
}
you can use this way by using references you want set cells.