I've got a fairly simple scenario:
The data structure i am expecting essentially looks like this (the actual layout is way more complicated):
some title
n child text
n child text
n child text
some title
n child text
n child text
n child text
n child text
n child text
some title
n child text
some title
n child text
n child text
n child text
n child text
n child text
In my first attempt i rendered all of it using programmed constraints, which (as you might guess) worked, but performed really bad.
Naturally i went ahead and researched for ways to display dynamic nested content. Unfortunately i was unable to find a good generic way to do this, using cell recycling.
Now i just came up with an idea which seemed very creative, but uber hacky.
What i am going to do, to utilize cell recycling:
I will create a generic cell class to pass TableView.RegisterClassForCellReuse(typeof(MySpecialCell<ItemType, RandomTypeForUniqueness>), "MySpecialCell"+item.Count.ToString());
Setup my cell depending on child count.
My question:
Is there a less cringy way to solve this? (Because this sure feels ugly.)
This is what it should look like in the end:
PS: I really wish RegisterClassForCellReuse would accept factories :(
Follow this steps:
In .h , declare
NSMutableArray *arrayForBool;
NSMutableArray *arrPastOrder;
In .m ,
- (void)viewDidLoad {
arrPastOrder=[[NSMutableArray alloc] init];
int range=1+arc4random()%10;
for(int i=0;i<range;i++)
{
NSMutableArray *arrinside=[[NSMutableArray alloc] init];
int range2=3+arc4random()%5;
for(int j=0;j<range2;j++)
{
if(j==0)
[arrinside addObject:[NSString stringWithFormat:#"Some Header %i",i]];
else
[arrinside addObject:[NSString stringWithFormat:#"Subindex %i",j]];
}
[arrPastOrder addObject:arrinside];
}
arrayForBool=[[NSMutableArray alloc]init];
for (int i=0; i<[arrPastOrder count]; i++)
{
[arrayForBool addObject:[NSNumber numberWithBool:YES]];
}
}
#pragma mark -
#pragma mark TableView DataSource and Delegate Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([[arrayForBool objectAtIndex:section] boolValue])
{
return [[arrPastOrder objectAtIndex:section] count]-1;
}
else
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *cellid=#"hello";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellid];
if (cell==nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellid];
}
BOOL manyCells = [[arrayForBool objectAtIndex:indexPath.section] boolValue];
/********** If the section supposed to be closed *******************/
if(!manyCells)
{
cell.backgroundColor=[UIColor clearColor];
NSLog(#"cellForRowAtIndexPath---if");
cell.textLabel.text=#"";
}
/********** If the section supposed to be Opened *******************/
else
{
//cell.textLabel.text=[NSString stringWithFormat:#"%# %ld",[sectionTitleArray objectAtIndex:indexPath.section],indexPath.row+1];
// ic_keyboard_arrow_up_48pt_2x ic_keyboard_arrow_down_48pt_2x.png
cell.textLabel.text=[NSString stringWithFormat:#"%#",[[arrPastOrder objectAtIndex:indexPath.section] objectAtIndex:indexPath.row+1]];
}
cell.textLabel.textColor=[UIColor blackColor];
return cell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [arrPastOrder count];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%li--%li",(long)indexPath.section, (long)indexPath.row);
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[arrayForBool objectAtIndex:indexPath.section] boolValue]) {
return 40;
}
return 0;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 100;
}
#pragma mark - Creating View for TableView Section
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *sectionView=[[UIView alloc]initWithFrame:CGRectMake(0, 0, 540,100)];
sectionView.backgroundColor=[UIColor whiteColor];
sectionView.tag=section;
UILabel *viewLabel=[[UILabel alloc]initWithFrame:CGRectMake(10, 30, 530, 40)];
viewLabel.backgroundColor=[UIColor whiteColor];
viewLabel.textColor=[UIColor blackColor];
viewLabel.font=[UIFont boldSystemFontOfSize:20];
viewLabel.text=[NSString stringWithFormat:#"%#",[[arrPastOrder objectAtIndex:section] objectAtIndex:0]];
[sectionView addSubview:viewLabel];
/********** Add UITapGestureRecognizer to SectionView **************/
UITapGestureRecognizer *headerTapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(sectionHeaderTapped:)];
[sectionView addGestureRecognizer:headerTapped];
return sectionView;
}
#pragma mark - Table header gesture tapped
- (void)sectionHeaderTapped:(UITapGestureRecognizer *)gestureRecognizer{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:gestureRecognizer.view.tag];
//Get which section is open, from here Set the value of arrafool. and expand collapse. Normally whole table is expanded.
}
Just run it. You will get the same structure. happy Coding !!
Related
I want to add button inside UITableView with drag and drop but i don't know how to call them inside UITableviewCell.You can see a keyword Desc where I have to set them as button title so that I can get all values which I placed in coreData frameWork.
-(void)setquestions:(int)qid
{
NSManagedObject *singleobject = nil;
singleobject = AllQuestions[qid];
NSString * desc=[singleobject valueForKey:#"questionDesc"];
questionlabel.text=desc;
int qidns=[[singleobject valueForKey:#"questionId"]intValue];
NSArray *dummy=[self getoptions:qidns];
NSLog(#"--inside setquestion-%lu",(unsigned long)dummy.count);
for (int i=0; i<dummy.count; i++) {
NSManagedObject *singleobject = nil;
singleobject = dummy[i];
NSString * desc=[singleobject valueForKey:#"optionDesc"];
[self addbutton:desc bid:i];
}
}
-(void)addbutton:(NSString *)desc bid:(int)bid{
[[QBFlatButton appearance] setFaceColor:[UIColor colorWithWhite:0.75 alpha:1.0] forState:UIControlStateNormal];
[[QBFlatButton appearance] setSideColor:[UIColor colorWithWhite:0.55 alpha:1.0] forState:UIControlStateNormal];
optionButton = [QBFlatButton buttonWithType:UIButtonTypeCustom];
optionButton.faceColor = [UIColor colorWithRed:0.400f green:0.737f blue:0.761f alpha:1.00f];
optionButton.sideColor = [UIColor colorWithRed:0.400f green:0.737f blue:0.761f alpha:1.00f];
optionButton.radius = 4.0;
optionButton.margin = 4.0;
optionButton.depth = 3.0;
[optionButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
optionButton.titleLabel.font=[UIFont systemFontOfSize:12];
optionButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
// you probably want to center it
optionButton.titleLabel.textAlignment = NSTextAlignmentCenter;
optionButton.tag=bid;
[optionButton setTitle:desc forState:UIControlStateNormal];
optionButton.frame = CGRectMake(5,bid*55,optionsview.frame.size.width-10, 50);
[optionsview addSubview:optionButton];
}
- (void)logItems {
int index = 0;
for ( NSString *str in self.items ) {
NSLog(#"%d: %#", index++, str);
}
}
#pragma mark - UITableViewDataSource, UITableViewDelegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.items count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [table dequeueReusableCellWithIdentifier:#"Cell"];
if ( cell == nil ) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
return cell;
}
#pragma mark - Edit Mode
- (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleNone; // No Delete icon
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
[table deselectRowAtIndexPath:indexPath animated:YES];
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
// Can move cell
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
NSUInteger origins = sourceIndexPath.row; // Original position
NSUInteger to = destinationIndexPath.row; // Destination position
NSLog(#"Origin %lu, To %lu", (unsigned long)origins, (unsigned long)to);
NSString *swap = [self.items objectAtIndex:origin];// Item
[swap shouldGroupAccessibilityChildren];
}
As I understood from the question you want to get the button in the cell for that you can create a custom cell class and then call this custom cell inside the cellforrow function. You can call the button like this
customCell.button.title = "some-string"
If you want a custom button with a particular action added to each of the cells, first you need to create a custom UI cell(using XIB since you need to drag and drop). Then add the button to that, and connect the button's IBAction and IBOutlet to the custom subclass for the cell. Next Add a protocol with a function to the cell subclass so that you can send a callback to the ViewController when the button is clicked. Now implement the delegate in the ViewController and use this cell for your purpose. If the delegate function returns the cell, you can figure out which cell's button is clicked, hence getting the indexpath to perform required action.
I create a subview for create a custom pickerview, I use a tableview item for do it, I need to have a different color only for the middle cell, for example if I have 3 visible row I need to have grey,black,grey, for do it I try in this way:
- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *visibleCells = [tableView visibleCells];
for (int i = 0; i < [visibleCells count]; i++) {
if (i == 1) {
UITableViewCell *cell = [visibleCells objectAtIndex:i];
[cell.textLabel setTextColor:[UIColor blackColor]];
}
}
}
the first time tableview appear is good but if I scroll I get first 2 or last 2 cell of one color and the remaining cell have the other color. How can I solve the problem?
Quick answer:
- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *visibleCells = [tableView visibleCells];
for (int i = 0; i < [visibleCells count]; i++) {
if (i == 1) {
UITableViewCell *cell = [visibleCells objectAtIndex:i];
[cell.textLabel setTextColor:[UIColor blackColor]];
}
else{
UITableViewCell *cell = [visibleCells objectAtIndex:i];
[cell.textLabel setTextColor:[UIColor grayColor]];
}
}
}
Explanation:
When you scroll a tableview.. the rows that are not visible are 'deleted' and 'recreated' when shown.. thats why there is a reuse identifier.. to reuse those cells.. if you reuse a cell with blackColor.. AS YOU DONT HAVE AN ELSE STATEMENT.. it will remain black.. even if you wanted it gray.. add the else statement to get the desired result.. GL HF
In my app, I have created a mutable array named "array".
array=[[NSMutableArray alloc]initWithObjects:#"a",#"b",#"c",#"d",#"e", nil];
My tableView contains only one row for multiple section, Each section has a customView which contains only one label.
My custom View name is ContentOfCell
ContentOfCell * contentOfCell=[[ContentOfCell alloc]initWithFrame:CGRectMake(0, 0, 100, 50)];
[cell.contentView addSubview:contentOfCell];
I have added the array to the label
contentOfCell.label.text=[array objectAtIndex:indexPath.section];
My problem is that it recognises only the first 4 values in the array and the first 4 values is getting repeated in the sections
I thing something is going wrong here
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [indexPath row]+50;
}
If I change 50 by 100, the error occurs if not the values are inserted correctly
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString * cellIdentifier=[NSString stringWithFormat:#"MyTableView"];
cell=[myTableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell== nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
ContentOfCell * contentOfCell=[[ContentOfCell alloc]initWithFrame:CGRectMake(0, 0, 100, 50)];
[cell.contentView addSubview:contentOfCell];
contentOfCell.nameField.text=[arr objectAtIndex:indexPath.section];
cell.contentView.backgroundColor=[UIColor whiteColor];
}}
Here the view contains only 3 rows, when I scroll down the array is initiated again, then the values are printed again
I guess you are not reusing the cell correctly.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString * cellIdentifier=[NSString stringWithFormat:#"MyTableView"];
cell=[myTableView dequeueReusableCellWithIdentifier:cellIdentifier];
ContentOfCell *contentOfCell;
//Initialization Part. declare objects here
if(cell== nil)
{
//Creation part. Create your new cell here. Do all UI actions here
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
contentOfCell=[[ContentOfCell alloc]initWithFrame:CGRectMake(0, 0, 100, 50)];
contentOfCell.tag =100;
[cell.contentView addSubview:contentOfCell];
cell.contentView.backgroundColor=[UIColor whiteColor];
}
else{
// Reusable part. Reuse the UI controls here from existing cell
contentOfCell = (ContentOfCell *)[cell.contentView viewWithTag:100];
}
//Assign all the data here
contentOfCell.nameField.text=[arr objectAtIndex:indexPath.section];
}
This is one of the simple mistake often committed by iOS Rookies.
Kindly check the Apple developer documentation here to understand how a tableview cell is reused
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/tableview_iphone/TableViewCells/TableViewCells.html
I implemented same code as below with grouped table.Everything is fine.Please compare your code with below code.
- (void)viewDidLoad
{
[super viewDidLoad];
arrData=[[NSMutableArray alloc] initWithObjects:#"a",#"b",#"c",#"d",#"e",#"f",#"g",#"h",#"i",#"j",#"k", nil];
// Do any additional setup after loading the view, typically from a nib.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arrData count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
return 50.0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *aCell=[tableView dequeueReusableCellWithIdentifier:#"da"];
if(aCell==Nil)
{
aCell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"da"];
ContentOfCell *ContentOfCellObj=[[ContentOfCell alloc] initWithFrame:CGRectMake(0,0,320,50)];
ContentOfCellObj.tag=101;
[aCell.contentView addSubview:ContentOfCellObj];
}
ContentOfCell *ContentOfCellObj=(ContentOfCell*)[aCell.contentView viewWithTag:101];
ContentOfCellObj.nameField.text=[NSString stringWithFormat:#"%#",[arrData objectAtIndex:indexPath.section]];
return aCell;
}
Use this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * cellIdentifier=#"CellIdentifier";//or your custom name
UITableViewCell* cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell== nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
ContentOfCell * contentOfCell=[[ContentOfCell alloc]initWithFrame:CGRectMake(0, 0, 100, 50)];
contentOfCell.tag = 101;
[cell.contentView addSubview:contentOfCell];
cell.contentView.backgroundColor=[UIColor whiteColor];
}
ContentOfCell * contentOfCell = (ContentOfCell*)[cell.contentView viewWithTag:101];
contentOfCell.nameField.text=[arr objectAtIndex:indexPath.section];
return cell;
}
Make sure you set
myTableView.dataSource = self;
and these two delegate methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [arrData count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
Try this code, surely it will resolve your problem.
Step 1. First declare array as global variable
#interface YOUR-CLASS-NAME ()
{
NSMutableArray *array
}
Step 2. Now set no of sections you need. This means how many time do you want to repeat the array values in table continuously.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
Step 3. Now set no of rows you need to display from your array. This means no of values from your array need to display
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [array count];
}
I am trying to set up a table index but it is showing up as a white bar on the right. I am using storyboard. Does anyone know what is going on? Thanks
Code:
#pragma mark - Tableview datasource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections in a tableview
return self.arrayOfCharacters.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return the height of each cell
return 55;
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
// Return table index
return [NSArray arrayWithArray: [#"A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|#" componentsSeparatedByString:#"|"]];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
// Match the section titls with the sections
NSInteger count = 0;
// Loop through the array of characters
for (NSString *character in self.arrayOfCharacters) {
if ([character isEqualToString:title]) {
return count;
}
count ++;
}
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the each section
return [[self.objectsForCharacters objectForKey:[self.arrayOfCharacters objectAtIndex:section]] count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
// Return the title for each section
return [NSString stringWithFormat:#"%#", [self.arrayOfCharacters objectAtIndex:section]];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"preplanCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
// Create a pointer to our preplan
LBPrePlan *preplan = [[self.objectsForCharacters objectForKey:[self.arrayOfCharacters objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
cell.textLabel.text = preplan.name;
cell.detailTextLabel.text = preplan.address;
return cell;
}
Found my problem. With iOS7 you have the ability to set sectionIndexBackgroundColor. Turns out it was working the whole time.
You can change the tableview indexset background color in ios7 using the following code
[[UITableView appearance] setSectionIndexBackgroundColor:[UIColor clearColor]];
[[UITableView appearance] setSectionIndexTrackingBackgroundColor:[UIColor lightGrayColor]];
[[UITableView appearance] setSectionIndexColor:[UIColor darkGrayColor]];
I insert a segmented in uitableview like this url image. If you see the url image, now i'm working ok everything data in uitable,
and...
When i scroll down table i wanna part 1: Image(in url) will scroll scroll to part 2: segmented will stop and if you still scroll uitable part 3: the data will be scroll (keep segmented on the top).
Have you any idea it. Thanks
I just test it, it is working!
Set your UITableView pain
UITableView has two section and each section has only one row.
When edit your section header, make sure only second section has header - second header will be your part2.
first section first row is your part1.
second section first row is your part3.
That's it : )
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 1;
}
- (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];
}
cell.textLabel.text = #"test";
return cell;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
#try {
UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 30)];
switch (section) {
case 0:
{
//nothing
}
break;
case 1:
{
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 30)];
lbl.text = #"second";
lbl.textColor = [UIColor blackColor];
[containerView addSubview:lbl];
}
break;
}
return containerView;
}
#catch (NSException *exception) {
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 30;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 1000.0;
}