Multi-View TableView with RootController - objective-c

I am trying to create a multi-view app with navigation template. I want table on the bottom part of initial view, with other views (image view, labels, etc) on the top.
Originally I modified RootViewController.xib to resize tableview, and added image view, but nothing displayed except full-size table.
So I modified RootViewController.xib to add UIView, then added a UITableView and UIImageView to that view. I added IBOutlet for the tableView. In my RootViewController.xib, File'S Owner (RootViewController) has outlet connection to the view and the table view. When I right-click the UITableView, I see the referencing outlet to File's Owner. When I right-click the UIView, I see the referencing outlet to File's Owner. (I don't have an outlet to UIImageView, since I don't modify in code; do I need one?).
However, when I launch the app, it crashes with message:
'NSInternalInconsistencyException',
reason: '-[UITableViewController loadView] loaded the "RootViewController" nib but didn't get a UITableView.'
Here is the cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *QuizIdentifier = #"QuizIdentifier";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:QuizIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:QuizIdentifier]
autorelease];
}
// Configure the cell.
UIImage *_image = [UIImage imageNamed:#"icon"];
cell.imageView.image = _image;
NSInteger row = [indexPath row];
cell.textLabel.text = [_categories objectAtIndex:row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}

You're getting that error because when you create a navigation-based iOS app, Xcode makes the RootViewController a subclass of UITableViewController. Once you combine that UITableView with a normal UIView, your subclass no longer complies with the UITableViewController class. So, in your RootViewController.m and .h files change UITableViewController to UIViewController. You may also need to change a few other things in your init method, but let's just start with this.
Try this:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"\n\nI'm in Root / cellForRowAtIndexPath");
static NSString *QuizIdentifier = #"QuizIdentifier";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:QuizIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:QuizIdentifier]
autorelease];
UIImage *_image = [UIImage imageNamed:#"icon"];
cell.imageView.image = _image;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Configure the cell.
NSInteger row = [indexPath row];
cell.textLabel.text = [_categories objectAtIndex:row];
NSLog(#" We are at row %i with label %# ", row, cell.textLabel.text);
return cell;
}

Related

Set text to textfield of table Cell in objective c outside UITableView delegate methods

I am new to objective C,and have made a demo app.
In this app I am having a UITableView which contains textField.When I taps a button(sign in using Facebook), after successfully login from Facebook it come back to my TableView screen,at that time i want to set values came from Facebook response to UITableView's textFields, but I am unable to do it as TableView's delegate method is calling only once.
Can anybody please help me to set text to tableView's textField outside its delegate method?
code
NSString *cellIdentifier = [[signInTableData objectAtIndex:2] objectForKey:#"cellIdentifier"];
signUpCustomCell *cell = (signUpCustomCell *)[signUpTable dequeueReusableCellWithIdentifier:cellIdentifier];
//NSLog(#"=====my username cell====%#",indexPath);
if(cell == nil)
{
cell = (signUpCustomCell *)[[signUpCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.backgroundColor = [UIColor clearColor];
cell.tableField.delegate = self;
CGRect frmTxt = cell.tableField.frame;
frmTxt.size.width = signUpTable.frame.size.width + TRAIL_MARGIN_CELL_CONTENT;
cell.tableField.frame = frmTxt;
cell.tableField.text = #"hello test";
If you know at which row your UITextField is then you can query UITableView for a cell at given IndexPath.
NSIndexPath *ip = [NSIndexPath indexPathForRow:0 inSection:0];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:ip];
You'll need to cast that cell to what ever custom cell you are using to access the UITextField inside and your custom UITableViewCell should have a property that points to the UITextField or a method that would update the text.
-(void)viewWillAppear or -(void)viewDidApper overrides in your UIViewController subclass could be the places to do that, after you have loaded your data to the UITableView.
You need to set values into UITextField in delegate
cellForRowAtIndexPath as it is rendered for every cell of UITableView.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"yourcellidentifier"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"yourcellidentifier"] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.yourTextView.text= textforRow;
return cell;
}

UINavigationController not pushing

I have two UITableViews embedded in a UINavigationController. The selection of a cell in the first table viewcontroller should trigger a push segue to the second. This segue is not being performed.
FirstTableVC
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// getting called as planned
if (indexPath.row == 0 && reload == YES) {
// working
[self pushedRefresh:self];
reload = NO;
return;
}
NSLog(#"past return"); // logged as planned
// NOT performing!
[self performSegueWithIdentifier:#"more" sender:[self.tableView cellForRowAtIndexPath:indexPath]];
}
What I've done/noticed
SecondTblVC's viewDidLoad: method is not being called. However, if I use non-push segues, the VC is presented correctly.
I've tried using nil and self in the sender parameter for performSegueWithIdentifier: with the same results.
I've converted the second view controller into a vanilla UIViewController with the same results.
The "more" segue is correctly labeled and connected as push
There's no crash, just lack of segue.
I've deleted the entire UINavigationController setup in storyboard and replaced it with the same results.
I do not have a separate .h/.m for the UINavigationController
Table view delegates/data source links are working as planned.
There is a destinationViewController (learned from logging in performSegue method).
Please let me know if more code and screenshots would help.
Thank you.
Edit
Here's my cellForRowAtIndexPath implementation:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"ReuseCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
cell.textLabel.text = [clubNames objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [times objectAtIndex:indexPath.row];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:simpleTableIdentifier];
}
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
Try using table view controller instead of table view
In your storyboard, create a storyboard ID for each of the UITableViewControllers, i.e.: vc1 and vc2
In your vc1 function, lookup the storyboard ID for the second table view controller,
which is :
UITableViewController *vc2 = [self.storyboard
instantiateViewControllerWithIdentifier:#"vc2"];
[self.navigationController pushViewController:vc2 animated:YES];

Pushing to a Detail View from a Table View Cell using Xcode Storyboard

I have a table view inside a View Controller. I can populate all my information inside the table view. However I am a bit lost for setting up the detail views. I believe each table cell needs a segue to a each detail view but not completely sure.
Here is my code. What am I missing to accomplish the segue from the table view to the detail views?
Code:
.h
#interface DetailViewController : UIViewController <UITableViewDelegate,UITableViewDataSource>
{
IBOutlet UITableView *myTable;
NSMutableArray *contentArray;
}
#property (strong, nonatomic) IBOutlet UITableView *myTable;
.m
- (void)viewDidLoad
{
contentArray = [[NSMutableArray alloc]init];
[contentArray addObject:#"Espresso"];
[contentArray addObject:#"Latte"];
[contentArray addObject:#"Capicino"];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
//Table Information
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [contentArray count];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if([[contentArray objectAtIndex:indexPath.row]isEqualToString:#"EspressoViewController"])
{
EspressoViewController *espresso = [[EspressoViewController alloc]initWithNibName:#"EspressoViewController" bundle:nil];
[self.navigationController pushViewController:espresso animated:YES];
}
else if ([[contentArray objectAtIndex:indexPath.row] isEqualToString:#"Latte"])
{
LatteViewController *latte = [[LatteViewController alloc] initWithNibName:#"Latte" bundle:nil];
[self.navigationController pushViewController:latte animated:YES];
}
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
[self tableView:tableView didSelectRowAtIndexPath:indexPath];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"CellIdentifier"];
}
NSString *cellValue = [contentArray objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.font = [UIFont systemFontOfSize:16];
cell.detailTextLabel.text = #"Hot and ready";
UIImage *image = [UIImage imageNamed:#"coffeeButton.png"];
cell.imageView.image = image;
cell.textLabel.text = [contentArray objectAtIndex:indexPath.row];
return cell;
}
I think you made this a little too complicated. Don't worry, I do the same thing often.
First, by sending tableView:didSelectRowAtIndexPath: from within tableView:accessoryButtonTappedForRowAtIndexPath: there is no difference between the two methods. Tapping the cell, or it's accessory button performs the same action. If you don't need the accessory button to perform a different action than tapping the cell itself, remove it.
Second, if you're using a storyboard, you do not need to alloc/initWithNib for your view controllers. Instead, use a segue. If you do this through the storyboard, you also don't need to programmatically push viewControllers onto your navigationController
Build your storyboard first:
Drag out a UITableViewController. Make sure you set the class of the UITableViewController you dragged out to your own "DetailViewController" using the inspector pane on the right side.
Then select this controller and using the menus choose "Editor->Embed In->Navigation Controller".
Next, drag out three generic UIViewControllers. Set the class of one to "LatteViewController", another to "EspressoViewController", and a third to "CapicinoViewController" (using the inspector again).
Control+drag from the UITableViewController over to each of these viewControllers and choose PUSH.
Click on the little circle that's on the arrow between your UITableViewController and each of these viewControllers. In the inspector (on the right side), give each segue a unique name in the Identifier field. You will need to remember this name for your code. I would name them "EspressoSegue", "LatteSegue", and "CapicinoSegue". You'll see why in the code below.
Then put the following code in your UITableViewController:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
//Build a segue string based on the selected cell
NSString *segueString = [NSString stringWithFormat:#"%#Segue",
[contentArray objectAtIndex:indexPath.row]];
//Since contentArray is an array of strings, we can use it to build a unique
//identifier for each segue.
//Perform a segue.
[self performSegueWithIdentifier:segueString
sender:[contentArray objectAtIndex:indexPath.row]];
}
How you implement the rest is up to you. You may want to implement prepareForSegue:sender: in your UITableViewController and then use that method send information over to segue.destinationViewController.
Note that I passed the string from your contentArray as the sender for the segue. You can pass whatever you like. The string that identifies the cell seems like the most logical information to pass, but the choice is up to you.
The code posted above should perform the navigation for you.

Detailtext is not showing in case?

I have a case but the detailtext is not showing? Does anyone know what te problem is?
i used: UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIViewController *controller;
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
switch(indexPath.row) {
case 0:
{
NSLog(#"Case 0");
controller = [[wed1 alloc] init]; //WithStyle:UITableViewStylePlain];
[self.navigationController pushViewController:controller animated:YES];
cell.detailTextLabel.text = #"Wedstrijden!";
}
break;
case 0:
{
NSLog(#"Case 0");
controller = [[wed1 alloc] init]; //WithStyle:UITableViewStylePlain];
//created a controller
[self.navigationController pushViewController:controller animated:YES];
//at his point, you are showing next ViewController's view
cell.detailTextLabel.text = #"Wedstrijden!";
//here you are changing the text of the text for current tableView's cell (which is actually going to be off the screen as new controller's view will be shown after previous statement execution)
}
with the piece of code you shared - I don't find anything wrong here, the detail text should not be visible as this view will be gone.
I don't fully understand why you'd want to set the detail text on a cell after pushing a new view controller. As samfisher said, when the user presses the first cell, in case 0, the new view controller will be alloc'd, init'd and then pushed, and after that you set the detail text to "Wedstrijden".
I'm assuming you're probably just confused between which property to use. My question to you is: when and where do you want this text to appear?
If the cell was created with the style UITableViewCellStyleDefault, the detail text label isn't displayed. In tableView:cellForRowAtIndexPath: implementation, you may create the cell with style UITableViewCellStyleSubtitle or UITableViewCellStyleValue1.
Use UIListContentConfiguration instead, or subtitle won't show.
#import <UIKit/UIListContentConfiguration.h>
And in the cellForRowAtIndexPath method:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"AddressCell" forIndexPath:indexPath];
if(cell==nil){
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"AddressCell"];
}
NSRange range = [self.dataArray[indexPath.row] rangeOfString:#","];
NSString *street;
NSString *restAddress;
if (range.location != NSNotFound) {
street = [self.dataArray[indexPath.row] substringToIndex:range.location];
restAddress= [self.dataArray[indexPath.row] substringFromIndex:range.location + 1];
}
UIListContentConfiguration *configuration = cell.defaultContentConfiguration;
configuration.text=street;
configuration.image=kImage(#"Location");
configuration.secondaryText=restAddress;
cell.contentConfiguration = configuration;
return cell;
}
Will look like this:

Animating a font size change in a UITableView

Hey Simple little app for educational purposes, its a simple uitableview and I want users to be able to use a uislider to adjust the font size as needed. The code I have now works to change the font but only when the view is updated, ie when i pull up or down the table view to reveal other cells. I'd like the font change to be reflected immediately as a user moves the uislider if possible, here's the code that I have working half way:
-(UITableViewCell *) tableView: (UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) indexPath {
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier];
if (cell == nil)
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier: SimpleTableIdentifier] autorelease];
NSUInteger row = [indexPath row];
cell.text = [listData objectAtIndex:row];
UIImage *image = [UIImage imageNamed:#"star.png"];
cell.font = [UIFont systemFontOfSize:[fontSlider value]];
cell.image = image;
return cell;
}
You could make an IBAction for the fontSlider for the "Value Changed" option as follows:
-(IBAction) refreshResize
{
[self.view setNeedsDisplay];
}
That should work. setNeedsDisplay refreshes the screen.