I have a UITableViewController that has 5 different sections, & each section contains an individual cell. In section 1 I have a UISegmentedControlthat offers two options by default segment 1 is picked so the rest of the sections (the other 4) correspond with segment 1. However, the problem that I am having is: Having the ability to switch to another UITableView that has other sections & cells that would correspond to segment 2, when of course segment 2 is selected in the UISegmentedControl
I am using storyboards for this project.
I know that the question of how to achieve this has been asked a thousand times, and I know how to do this if I was working with regular view controllers, I am new to working with UITableViewController and this is really giving me a hard time.
Things that I have tried:
No.1: I tried deleting the UITableViewController all together and replacing with a normal ViewController and sub a UITableView to the main view. The problem with that is that I was given an error by xcode because static cells require a UITableViewController to work, (unfortunately I am working with static cells).
No.2: I have tried to hide the cells with a conditional from the UISegmentedControl to only display the appropriate cells with the appropriate selection, but this did not work because I was not able to add my other sections & cells on top (as I would have normally done with regular UIViewController.
This is the code that I used to try method # 2 :
- (IBAction)segmentedControl:(id)sender {
UISegmentedControl *segmentedControl = (UISegmentedControl *) sender;
NSInteger selectedSegment = segmentedControl.selectedSegmentIndex;
if (selectedSegment == 0)
{
upick= 0;
self.lengthCell.hidden=NO;
self.widthCell.hidden=NO;
self.depthCell.hidden=NO;
self.flowCell.hidden=YES;
}
else if (selectedSegment == 1)
{
upick =1;
self.lengthCell.hidden=YES;
self.widthCell.hidden=YES;
self.depthCell.hidden=YES;
self.flowCell.hidden=NO;
}
}
No.3: Countless hours of research on the net but can't seem to find the exact results I am looking for, most show how to do this with a UIViewController and the steps are different for this particular case.
I would really appreciate some advice & overall direction to take from here because I am stuck. Thanks guys!
Have all the cells you need available in your table view controller.
In your table view's datasource methods (i.e. numberOfSections, numberOfRowsInSection, cellForRowAtIndexPath) you can set all the correct numbers and data for the two states.
When the segmented control changes, you can do two things. Either you simply reloadData, as was suggested before, but then you do not get any animations. Or you use insertRowsAtIndexPaths:withRowAnimation: and deleteRowsAtIndexPaths:withRowAnimation: to get the animation effect.
E.g. showing sections 1-2 in case 1 and sections 3-6 in case 2 (section 0 being the top section); each section has 2 rows
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return _control.selectedSegmentIndex == 0 ? 3 : 4;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return section == 0 ? 1 : 2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// .. the usual boilerplate
if (_control.selectedSegmentIndex == 0) { /* configure cell */ }
else { /*do the same for the other case */ }
return cell;
}
-(void)segmentedControlDidChange:(UISegmentedControl*)sender {
NSIndexSet *indexes;
[_tableView beginUpdates];
if (sender.selectedSegmentIndex == 0) {
indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1,4)];
[_tableView deleteSections:indexes
withRowAnimation: UITableViewRowAnimationFade];
indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1,2)];
[_tableView insertSections:indexes
withRowAnimation: UITableViewRowAnimationFade];
[_tableView reloadSections:indexes
withRowAnimation: UITableViewRowAnimationNone];
}
else {
// do the reverse
}
[_tableView endUpdates];
}
If I am correct, you need to switch between 2 table views using UISegmentedControl. You can use UIViewController and add 2 UITableViews to it and keep your UISegmentedControl outside the table views. Then may be you can manage it in the following method:
- (IBAction)segmentedControl:(id)sender {
UISegmentedControl *segmentedControl = (UISegmentedControl *) sender;
NSInteger selectedSegment = segmentedControl.selectedSegmentIndex;
if (selectedSegment == 0)
{
//show Table1 and hide Table2
// Reload Table1
}
else if (selectedSegment == 1)
{
//show Table2 and hide Table1
// Reload Table2
}
}
Hope this helps.
Related
I am trying to implement accordion tableview with parent and child custom tableview cells. I am using below mentioned open source code.
Source code : https://github.com/singhson/Expandable-Collapsable-TableView
In that code having single tableview with single tableview cell. It will show for parent and child cells but I want to make:
Main storyboard Tableview
Parenttableviewcell separate class and xib
Childtableviewcell separate class and xib
It should apply on main controller tableview with accordion. Right now in this code there is no separate custom cells (parent and child using same tableview cell and changing data only).
You can implement it by trying to manage the sections and rows of a table view, thats what i assume to be the simplest way to implement it without using any third party code. For example
All the section headers will contain their own number of rows.
Take a array or dictionary or array that will store the state of expanded rows in sections. (Say '1' for expanded state and '0; for collapsed state)
If in the initial state, all the UI is expanded then set all the objects '1' in array or dictionary.
On tap of individual headers (I am assuming section will be collapsed on click on individual header of section) you can get which section need to be collapsed. Retain this state as '0' for collapsed section rows in the array or dictionary.
Reload the table and check in heightForRow delegate method for the '0' entity in your array or dictionary. Wherever you find it to be '0', return height as 0 in the delegate method.
Perform the opposite for reverse functionality.
UPDATE FOR CODE
- (IBAction)btnMenuViewTypeTapped:(id)sender{
UIButton *btnSender = (UIButton *)sender;
if(menuViewType == MVTCollapse){
[btnSender setImage:[UIImage imageNamed:#"MenuCollapse"] forState:UIControlStateNormal];
menuViewType = MVTExpand;
for(NSInteger intAtIndex=0; intAtIndex<[mutArrSearchMenuItems count]; intAtIndex++){
[mutArrSectionOpened replaceObjectAtIndex:intAtIndex withObject:#"1"];
}
} else{
[btnSender setImage:[UIImage imageNamed:#"MenuExpand"] forState:UIControlStateNormal];
menuViewType = MVTCollapse;
for(NSInteger intAtIndex=0; intAtIndex<[mutArrSearchMenuItems count]; intAtIndex++){
[mutArrSectionOpened replaceObjectAtIndex:intAtIndex withObject:#"0"];
}
}
[tblViewRestaurantMenu reloadData];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [mutArrSearchMenuItems count];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
NSInteger intNumOfRow;
if([mutArrSectionOpened[section] isEqualToString:#"1"]){
intNumOfRow = [mutArrSearchMenuItems[section][strMenuType] count];
}
else{
intNumOfRow = 0;
}
return intNumOfRow;
}
You can implement it by using SKSTableview.
for that Please refer the below link:
SKSTableView
Let make two kinds of custom cell.
+Parent cell is tableview sectionHeader
+Child cell is normal cell
/*your datasource like this
arrData = #[section, section, section ....]
section.name
section.image
section.arrayChild
arrayChild = #[child, child, child....]
child.name
child.image
*/
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return arrData.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
section = arrData[section];
child = section.child;
return child.count;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
//Cell is Custom of UITableViewHeaderFooterViewCell
//load your Parent Cell here
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//load your custom chill cell here
}
I Have a one table view and i have two array. My arrays name AllItems and SpecialItems. I Use segment control. I wantto if segment value is 0 tableview load AllItems Array, When change segment value and value is = 1 than mytableview reload tada but SpecialItems array. Can u help me please. Thanks.
I solved this problem with table tag.
- (IBAction)segmentControlChanged:(UISegmentedControl *)sender {
if (sender.selectedSegmentIndex == 1) {
mytable.tag = 1;
}
else
{
mytable.tag = 0;
}
[mytable reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(tableView.tag==1)
{
return [specialItems count];
}
else
return [allItems count];
}
You could create two data source classes that implement all the UITableViewDataSource methods: one for AllItems and one for SpecialItems. To switch between the two, connect a valueChanged action. In the method that is called, set the data source and reload the table view.
- (void)valueChange:(UISegmentedControl *)sender
{
if (/* condition for all items */) {
self.tableView.dataSource = self.allItemsDataSource;
} else {
self.tableView.dataSource = self.specialItemsDataSource;
}
[self.tableView reloadData];
}
I would personally create an array which the data is loaded from. Put this in your implementation:
NSArray * _tableData
Then in your viewDidLoad just allocate this for the array which we want it to start on.
_tableData = [[NSArray alloc] initWithArray:allItems];
This initially loads the data we will always see as the segment control starts on index 0. We have to set the initial data somewhere so the tableView loads with some data in it.
Then set the number of rows and the cellForRowAtIndex to pick up from the _tableData array
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _tableData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView_ cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [tableView_ dequeueReusableCellWithIdentifier:bCell];
// Here we use the specific array as we would normally
return cell;
}
This step means the tableView will load with the array. Even if the array is empty the view will still load as the number of cells will be zero.
Now in our value changed function we can reset the array as we need to:
- (IBAction)segmentControlChanged:(UISegmentedControl *)sender {
if (sender.selectedSegmentIndex == 1) {
_tableData = allItems;
}
else {
_tableData = specialItems;
}
[self.tableView reloadData];
}
You just need to make sure the segment control changed is linked up in the XIB file (or programatically) and that you reload the table after choosing the array.
This kind of thing is actually really easy to do. I would definitely recommend working it through step by step if you're having trouble. Make sure each step is working before applying the next:
Get the tableView loading with both sets of data individually
Confirm that the segment control is calling the change function when clicked
Then that should do it
I have a UITableView with static cells created in a storyboard. When the user touches a cell, another cell should hide/show. This is identical to how it looks in the built-in calendar app in iOS 7. It's basically the same question as this: How does one implement a view that slides out like the date picker in calendar? but I have a static table view and not a dynamic, otherwise the solution would have worked. If i try it, en exception is thrown.
As it is now, I can show and hide the cell at the row, but it is without animation, which isn't acceptable. This is the code I use:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 2 && indexPath.row == 0)
{
NSIndexPath *dateIndexPath = [NSIndexPath indexPathForRow:1
inSection:2];
UITableViewCell *dateCell = [self.tableView cellForRowAtIndexPath:dateIndexPath];
if (dateCell.hidden)
{
dateCell.hidden = NO;
}
else
{
dateCell.hidden = YES;
}
}
}
hye, i think you should refer this link, it will help you regarding hiding cells,
UITableView set to static cells. Is it possible to hide some of the cells programmatically?
I have 2 sections on my UITableview controller. One of my section has a switch and my requirement is when I set the switch to ON, the second section should be set to hidden along with all its rows. I am calling the following method/code to hide the section when the status of the switch is changed:
- (void)setState
{
myTableViewCell *myCell = [[myTableViewCell alloc] init];
if ([myCell.mySwitch isOn])
{
NSIndexPath *indexPath = [NSIndexPath indexPathWithIndex:1];
[self.tableView cellForRowAtIndexPath:indexPath].hidden = YES;
}
}
I am getting the following exception for this code which I understand is perfectly true.
Name = NSInternalInconsistencyException;
Reason = "Invalid index path for use with UITableView. Index paths passed to table view must contain exactly two indices specifying the section and row. Please use the category on NSIndexPath in UITableView.h if possible.";
But how can I hide the complete section along with all its rows. If I try to get the index path using NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:1]; this would just hide the 1st row in the section.
If you wanna hide a whole section when switch is on, just reloadData when you click the switch, and return 0 in numberOfRowsInSection for that section and return totalNumberOfSections - howManySwitchesIsOn in numberOfSectionsInTableView, like this:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if(howManySwitchesIsOn) {
return totalNumberOfSections - howManySwitchesIsOn;
}
return totalNumberOfSections;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(section should be hide) {
return 0;
}
return howManyRowsForThatSection;
}
Section deletion and insertion in a grouped UITableView are accomplished via:
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
Check out SectionHidingDemo, a demo app that illustrates section deletion and insertion in a grouped UITableView using those methods.
I'm adding a row to a UITableView section when the user switches the table to editing mode with this code:
- (void) setEditing:(BOOL) editing animated:(BOOL) animated {
[super setEditing:editing animated:animated];
if (editing) {
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject: [NSIndexPath indexPathForRow:0 inSection:SECTION_SUPPLIERS]] withRowAnimation:UITableViewRowAnimationFade];
}
}
The object being to create a "Add new supplier ..." row. This works, however when the table wants to get the editing style so it can add a plus or minus icon, I have a problem.
- (UITableViewCellEditingStyle) tableView:(UITableView *) tableView editingStyleForRowAtIndexPath:(NSIndexPath *) indexPath {
return ([self.tableView isEditing] && indexPath.row == 0) ? UITableViewCellEditingStyleInsert : UITableViewCellEditingStyleDelete;
}
The sequence seems to go like this:
The table switches to editing. There is only one supplier row at this time so it queries for a editing style with row == 0.
The insert of the new row is done which then triggers another query for an editing style again with a row == 0.
So if I use this sequence and use the row number and tableView isEditing to decide on the editing style icon I end up with both the Add new and current supplier rows with plus icons on them.
What is the best way to insert a row and assign the appropriate editing style - plus for the add new row, and minus for any other row?
Have you tried putting your "Add new..." row at the bottom instead of at the top? Instead of checking for [indexPath row] == 0 you instead check for [indexPath row] == [items count], and your tableView:numberOfRowsInSection: implementation looks like this:
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
int numberOfRows = [items count];
if ([self isEditing]) {
numberOfRows++;
}
return numberOfRows;
}
This is how the example in iPhone Programming: The Big Nerd Ranch Guide works.