UA-17470720-3

Jump to content


Photo
- - - - -

Add Disclosure button to cells


  • Please log in to reply
10 replies to this topic

#1 Troy

Troy

    Starting Out

  • STV 2.0
  • Pip
  • 8 posts
Reputation: 1
Good

Posted 14 March 2011 - 06:10 PM

Hello,
I just purchased STV and so far, I must say I am amazed at how easy it is so far. Watched the videos, and within about 10-15 minutes I had a basic app running that would have taken my hours to do without STV.

I am trying to figure out how to add a Detail Disclosure button to my table.

To give you an analogy of what I am trying to do, I have the following entities: State, County, and City. So far, I have my app setup following the basic structure of the Core Data sample app, and have the State entity implemented so far. When the Detail Disclosure button is selected, I want the State detail view to display. When the cell is selected, I want to drill-down and display all of the Counties in the selected State.

With a UITableViewCell, I was using cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton in the cellForRowAtIndexPath method. Then in the didSelectRowAtIndexPath method, I would push the Cities view controller onto the navigation stack. In the accessoryButtonTappedForRowWithIndexPath method, I would push the State detail view onto the navigation stack.

Any assistance you can provide would be greatly appreciated.

Thank you,
Troy

#2 Tarek

Tarek

    Forum Admin

  • Administrators
  • 3670 posts
Reputation: 452
Popular

Posted 14 March 2011 - 06:51 PM

Hi Troy,

Thanks a lot for all the complements :)

You can do what you're asking for through STV's SCTableViewModelDelegate methods (please make sure you conform to the SCTableViewModelDelegate protocol in your view controller's header file). First, you need to implement the willConfigureCell method:

- (void)tableViewModel:(SCTableViewModel *)tableViewModel 
  willConfigureCell:(SCTableViewCell *)cell 
  forRowAtIndexPath:(NSIndexPath *)indexPath
{
  // Make sure the current section is an SCArrayOfObjectsSection before
  // modifying the cell's accessory type
  SCTableViewSection *section = [tableViewModel sectionAtIndex:indexPath.section];
  if([section isKindOfClass:[SCArrayOfObjectsSection class]])
	cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}

This will actually modify the cells in the main model only, and not the rest of the detail models' cells. This is because only the main model has its "delegate" property set automatically to your view controller. To have the "willConfigureCell" method get called for the rest of the detail models, you'll have to set their delegates using the following methods:

// Method is called when a detail model is created for a new item
- (void)tableViewModel:(SCTableViewModel *)tableViewModel 
  detailModelCreatedForSectionAtIndex:(NSUInteger)index 
  detailTableViewModel:(SCTableViewModel *)detailTableViewModel
{
  detailTableViewModel.delegate = self;
}

// Method is called when a detail model is created for an existing item
- (void)tableViewModel:(SCTableViewModel *)tableViewModel 
  detailModelCreatedForRowAtIndexPath:(NSIndexPath *)indexPath
  detailTableViewModel:(SCTableViewModel *)detailTableViewModel
{
  detailTableViewModel.delegate = self;
}

With STV 2.0 final release (due before the end of this week), STV would automatically use the disclosure button to display the cell's detail view and you would be done here. Since you don't have the final release yet, you should manually tell STV to do that:

// Tell STV what to do when the disclosure button is tapped
- (void)tableViewModel:(SCTableViewModel *)tableViewModel
  accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
  SCTableViewSection *section = [tableViewModel sectionAtIndex:indexPath.section];

  // check if the section in an SCArrayOfObjectsSection
  if([section isKindOfClass:[SCArrayOfObjectsSection class]])
  {
	SCArrayOfObjectsSection *objectsSection = (SCArrayOfObjectsSection *)section;
	
	// Tell the section to dispatch the same event as if the cell itself was selected
	[objectsSection dispatchSelectRowAtIndexPathEvent:indexPath];
  }
}

Hope this helps!

#3 Troy

Troy

    Starting Out

  • STV 2.0
  • Pip
  • 8 posts
Reputation: 1
Good

Posted 14 March 2011 - 07:37 PM

Thank you for the quick response. I'm still trying to figure out how to code the didSelectRowAtIndexPath method. I've already tried searching the forums, so if you have already helped someone else with this, I apologize. I'm probably trying to over complicate things since I'm accustomed to doing this the old way using fetchedResultsController.

Thanks again.
Troy

#4 Tarek

Tarek

    Forum Admin

  • Administrators
  • 3670 posts
Reputation: 452
Popular

Posted 15 March 2011 - 09:21 AM

Hi again Troy,

Never mind at all! :)

Most of the time you won't need to do this while using STV, but if you do need to be informed when a cell gets selected, just implement the SCTableViewModelDelegate method called didSelectRowAtIndexPath:

- (void)tableViewModel:(SCTableViewModel *)tableViewModel 
  didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  // your code here
}

As I already said, most of the time STV takes care of everything for you, so you'd usually only implement this if you want to present your own custom view controllers or something. Please tell me if you need anything else.

#5 Troy

Troy

    Starting Out

  • STV 2.0
  • Pip
  • 8 posts
Reputation: 1
Good

Posted 15 March 2011 - 11:44 AM

Hi Tarek,
In the didSelectRowAtIndexPath, this is what I have so far:

- (void)tableViewModel:(SCTableViewModel *)tableViewModel 
  didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
   SCTableViewSection *section = [tableViewModel sectionAtIndex:indexPath.section];

   SCArrayOfObjectsSection *stateSection = (SCArrayOfObjectsSection *)section;

   NSManagedObject *stateObject = [stateSection.items objectAtIndex:indexPath.row];

   //I added an alert to indicate that I have correctly retrieved the selected State.
   //Trying to now display a SCTableViewModel listing the County entities for the selected stateObject. Based on what you shared with me earlier, the accessoryButtonTappedForRowWithIndexPath method is handling the default action for didSelectRowAtIndexPath.

}

Thanks again for all of your help.

Troy

#6 Tarek

Tarek

    Forum Admin

  • Administrators
  • 3670 posts
Reputation: 452
Popular

Posted 15 March 2011 - 12:02 PM

Hi Troy,

Glad everything is working well for you now. Please tell me if you need anything else.

#7 Troy

Troy

    Starting Out

  • STV 2.0
  • Pip
  • 8 posts
Reputation: 1
Good

Posted 16 March 2011 - 06:36 AM

Hi Tarek,
I'm still struggling to get this working.

Here is the code in my RootViewController:

- (void)tableViewModel:(SCTableViewModel *)tableViewModel 
  didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
   SCTableViewSection *section = [tableViewModel sectionAtIndex:indexPath.section];

   SCArrayOfObjectsSection *stateSection = (SCArrayOfObjectsSection *)section;

   NSManagedObject *stateObject = [stateSection.items objectAtIndex:indexPath.row];

   CountyViewController *countyController = [[CountyViewController alloc] initWithStyle:UITableViewStylePlain];
   countyController.stateObject = stateObject;

   [self.navigationController pushViewController:countyController animated:TRUE];
   [countyController release];
}

I created a regular view controller called CountyViewController, conformed to the SCTableViewModelDelegate protocol in the header file.

Here is the viewDidLoad in CountyViewController:

-(void)viewDidLoad {
   [super viewDidLoad];
   NSManagedObjectContext *managedObjectContext = [(TestAppAppDelegate *)[UIApplication sharedApplication].delegate managedObjectContext];

   //Create class definition
   SCClassDefinition *countyDef = [SCClassDefinition definitionWithEntityName:@"countyEntity" withManagedObjectContext:managedObjectContext withPropertyNames: [NSArray arrayWithObjects:@"name", @"countyExec", nil]];
   tableModel = [[SCTableViewModel alloc] initWithTableView:self.tableView withViewController:self];

   SCObjectSection *objectSection = [SCObjectSection sectionWithHeader:nil withBoundObject:[self stateObject] withClassDefinition:countyDef];

   [tableModel addSection:objectSection];
}

With selecting the cell, the detail view is displaying rather than the table view with list of counties. Can you help?

Thank you

#8 Tarek

Tarek

    Forum Admin

  • Administrators
  • 3670 posts
Reputation: 452
Popular

Posted 16 March 2011 - 04:13 PM

Hi Troy,

Would you please give me an overview what you're trying to achieve? Odds are STV will be able to do it automatically for you without you creating any custom detail view controllers.

#9 Troy

Troy

    Starting Out

  • STV 2.0
  • Pip
  • 8 posts
Reputation: 1
Good

Posted 17 March 2011 - 11:45 AM

Hi Tarek,
I'm attaching some images to illustrate what I am trying to accomplish. I'll go back to my analogy with States, Counties and Cities even though this isn't what my application is really using, but it follows the exact same concept.

The first image (called States Table List) is of the top-level table view, called States. You can see I have a disclosure detail button on each cell.

When the user taps the blue disclosure detail button, I want the State Detail View window to display. In my pre-STV version of the application, I was handling this in the accessoryButtonTappedForRowWithIndexPath method.

When the user taps the actual cell, I want to "drill-down" into the Counties Table List, which lists the Counties in the State the user selected. In this case, I selected New York and see four counties listed in the State of NY. In my pre-STV version of the application, I was handling this in the didSelectRowAtIndexPath method.

On the Counties Table List, the behavior would be the same where tapping the blue disclosure detail button would bring up the County Detail View, and tapping the actual cell would "drill-down" into a Cities Table List.

Thanks for your assistance.
Troy

Posted Image

#10 Troy

Troy

    Starting Out

  • STV 2.0
  • Pip
  • 8 posts
Reputation: 1
Good

Posted 17 March 2011 - 12:22 PM

The zip is too big to attach. Is there an e-mail address I can send it to?

Thanks,
Troy

#11 Tarek

Tarek

    Forum Admin

  • Administrators
  • 3670 posts
Reputation: 452
Popular

Posted 17 March 2011 - 02:35 PM

Hi Troy,

I think I now get what you want. Many ideas come to mind now on how to approach this, but I think this is the easiest way:

1- Create a BOOL member variable called accessoryButtonTapped and make sure it's initialized to FALSE before your view controller appears. We'll be using this variable inside the delegate methods to determine if the user tapped the cell's accessory button.

2- Make sure that the class definition of the "State" entity defines the counties relationship attribute. Similarly, make sure that the class definition of the "County" entity defines the cities relationship attribute. This is probably how you've already got them defined, but I just wanted to make sure this is the case.

3- Implement the following delegate methods (overwrite any delegates we discussed before)

- (void)tableViewModel:(SCTableViewModel *)tableViewModel 
  detailModelCreatedForRowAtIndexPath:(NSIndexPath *)indexPath
  detailTableViewModel:(SCTableViewModel *)detailTableViewModel
{
  // give the detail model a tag equivalent to its depth within the hierarchy so that it would be easily identified later on
  detailTableViewModel.tag = tableViewModel.tag + 1;

  // set the detail model's delegate
  detailTableViewModel.delegate = self;

  // If the accessory button wasn't tapped, change the detail navigation bar type to allow interacting with several objects
  if(!self.accessoryButtonTapped)
	((SCTableViewController *)detailTableViewModel.viewController).navigationBarType = SCNavigationBarTypeAddEditRight;
}

- (void)tableViewModel:(SCTableViewModel *)tableViewModel 
  willConfigureCell:(SCTableViewCell *)cell 
  forRowAtIndexPath:(NSIndexPath *)indexPath
{
  // Make sure the current section is an SCArrayOfObjectsSection before modifying the cell's accessory type
  SCTableViewSection *section = [tableViewModel sectionAtIndex:indexPath.section];
  if([section isKindOfClass:[SCArrayOfObjectsSection class]])
	cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}

- (void)tableViewModel:(SCTableViewModel *)tableViewModel
  accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
  SCTableViewSection *section = [tableViewModel sectionAtIndex:indexPath.section];
  if([section isKindOfClass:[SCArrayOfObjectsSection class]])
  {
	SCArrayOfObjectsSection *objectsSection = (SCArrayOfObjectsSection *)section;
	
	self.accessoryButtonTapped = TRUE;
	[objectsSection dispatchSelectRowAtIndexPathEvent:indexPath];
  }
}

- (void)tableViewModel:(SCTableViewModel *)tableViewModel 
  detailViewWillAppearForRowAtIndexPath:(NSIndexPath *)indexPath 
  withDetailTableViewModel:(SCTableViewModel *)detailTableViewModel
{
  SCObjectSection *section = 
	(SCObjectSection *)[detailTableViewModel sectionAtIndex:0];

  SCArrayOfObjectsCell *objectsCell = nil;
  switch(tableViewModel.tag)
  {
	case 0:  // main States model
	  objectsCell = [section cellForPropertyName:@"counties"]; // replace @"counties" with your actual relationship attribute name
	  break;
	case 1:  // Counties model
	  objectsCell = [section cellForPropertyName:@"cities"]; // replace @"cities" with your actual relationship attribute name
  }

  if(self.accessoryButtonTapped)
  {
	self.accessoryButtonTapped = FALSE;

	// just remove the objectsCell from the section
	NSIndexPath *objectsCellIP = [tableViewModel indexPathForCell:objectsCell];
	[section removeCellAtIndex:objectsCellIP.row];
  }
  else
  {
	// Create an SCArrayOfObjectsSection
	SCClassDefinition *classDef = nil;
	if([objectsCell.itemsClassDefinitions allValues].count)
	  classDef = [[objectsCell.itemsClassDefinitions allValues] objectAtIndex:0];
	SCArrayOfObjectsSection *objectsSection = 
	  [SCArrayOfObjectsSection sectionWithHeaderTitle:nil 
	   withItems:objectsCell.items withClassDefinition:classDef];
	objectsSection.addButtonItem = ((SCTableViewController *)detailTableViewModel.viewController).addButton;

	// Replace the current section altogether with the objectsSection 
	[detailTableViewModel removeSectionAtIndex:0];
	[detailTableViewModel addSection:objectsSection];
  }
}

This should be it! Please tell me if it works for you.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users