change labels in a view using a tableview - objective-c

First look at this screenshot please. What I want to do is when I click on a cell in the little tableview on the right. Then the labels should change to some other data. I am using a custom controller for my datasource and delegate. I'm setting the controller in my viewDidLoad.
- (void)viewDidLoad
{
tabelPlayers=[[tblPlayersDataSourceDelegate alloc]init];
tblPlayers.dataSource=tabelPlayers;
tblPlayers.delegate=tabelPlayers;
[tabelPlayers setTableSource:_playersArray];
}
In this tblPlayersDataSourceDelegate I do this for my didSelectCellAtIndexPath
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Team *player = [_tableSource objectAtIndex:indexPath.row];
PlayerDetailController *detail = [[PlayerDetailController alloc]init];
[detail setStrNaam:player.name];
[detail reloadInputViews];
}
But it doesn't change anything. Can somebody help me ?
Thanks in advance

If I understand your question right, what you're trying to do is change the information on the left labels according to the selected player from the little table view on the right.
I don't fully understand your code but what I would do as a general structure to achieve the same result as you are describing you want would be to:
Create an NSDictionary (could be in a *.plist file) that contains "Items" (inner NSDictionary's).
Each "Item" contains keys (player age, player's number or whatever).
The little table on the right will use another NSArray that will be constructed from the main NSArray keys:
NamesArray = [mainPlayersDictionary allKeys];
Whenever a row is selected in your small tableview you simply load all the labels according to the keys in your main NSDictionary:
[ageLabel setText: [[mainPlayersDictionary objectAtIndex:selectedRowIndex] objectForKey:plAge];
[pNumLable setText:[[mainPlayersDictionary objectAtIndex:selectedRowIndex] objectForKey:pNum];
And your set. Hope that helps.

Related

Presenting correct View Controller instance depending on cell selection in UITableView

I understand this might be covered in parts in answers to other questions (see references) I've seen on the site, but due to my limited experience I haven't been able to understand each part as it relates to my code. Please forgive me for any duplications.
I have a PFQueryTableViewController (essentially a UITableViewController) called threadsViewController that sources cell information from a Parse backend. The table view consists of threads similar to what you would see on a web forum.
I then have a separate class postsViewController which is another PFQueryTableViewController that I wish to display a table of all the responses ('posts') to that particular thread.
The functionality I'm looking for is for a user tapping on a thread (left screen in the image) to be presented with a postsViewController (right screen) containing only those posts/responses related to that thread. (See basic diagram below).
What I do know from my research:
The Parse backend is established with classes for Thread and Post.
I'm probably going to use the didSelectRowAtIndexPath delegate method
What I need help with:
How can I know which thread cell a user tapped on, and then pass that on so that the postsViewController only displays posts from that Thread?
A layman's description of how to use indexPath.row etc
I understand how to complete PFQueries etc to get the data for the cells, I just don't know how to implement the navigation and how to tell postsViewController which posts to show.
In case it helps somehow, here is my implementation so far. I have tried addign a property to the postsViewController called fromThread to somehow store the thread but apart from that I'm out of ideas!
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
postsViewController *postsVC = [[postsViewController alloc] init];
postsVC.fromThread = //?
[self performSegueWithIdentifier:#"threadsToPosts" sender:self];
}
References
How to filter a Parse query by an tableview index?
Pass Index Number between UITableView List segue
didSelectRowAtIndexPath and prepareForSegue implementation
You're on the right track. You need know how to do two things: (1) access your parse objects by indexPath, and (2) push a new view controller in a navigation controller.
(1) is simpler: PFQueryTableVC provides a method called objectAtIndexPath: that does just what you need.
// indexPath is the indexPath parameter to the didSelectRow delegate method
PFObject *fromThread = [self objectAtIndexPath:indexPath];
(2) is simple, too. But more complicated because there are a couple ways to do it. Segue is the more modern way, but I think the old way is simpler, and certainly easier to describe in code. View Controllers are given storyboard ids on the "Identity" tab in the storyboard editor. Give your Posts-presenting VC a storyboard id like "PostVC".
To get a new instance, use that storyboard id as follows:
MyPostVC *postVC = [self.storyboard instantiateViewControllerWithIdentifier:#"PostVC"];
// initialize it with the PFObject we got above
postVC.fromThread = fromThread;
// present it on the navigation stack
[self.navigationController pushViewController:postVC animated:YES];
And fromThread is just what the PostVC will need to form a query for posts associated with the selected thread.
You can pass data of cell to next ViewController in prepareForSegue with something like this
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"threadsToPosts"]) {
UINavigationController *navCon = segue.destinationViewController;
postsViewController *postsViewController = [navCon.viewControllers objectAtIndex:0];
// Whatever you are populating your tableView with
Thread *thread = [self.thread objectAtIndex:self.tableView.indexPathForSelectedRow.row];
postsViewController.thread = thread;
}
}

Update DetailView with MasterView in Master-Detail application - iPad

I am developing a master detail view application for iPad. All I have done so far is to get the data populated in my Master view. All these are images which are stored in NSMutableArray. When a user clicks on any row, The corresponding image should appear in the detail view.
I saw so many examples on this and I figured out that I need to make changes in didSelectRowAtIndexPath and in setDetailItem and configureView. But I don't know what exactly I have to do in these methods. Also, my Master view should be hidden when I select any row in it. This is not happening. Also, in iPad master detail template, there is no seague between the Master view and detail view. I tried creating one but then the data is being displayed in Master view only and not in detail view. I want the detail view to be updated. Please let me know if anyone know how to get this done.
You just need to get value of parameter that you want to pass to detail view.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.detailViewController) {
self.detailViewController = [[[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil] autorelease];
}
// Here you need to pass data object that you want to show in detail view Controller
// Object contains value of particular index in tableView.
self.detailViewController.detailItem = object;
[self.navigationController pushViewController:self.detailViewController animated:YES];
}

Playing songs with button in UITableView

I'm creating a custom table that has a button which allows a user to preview a song when pressed. Most of my code works but I haven't figured out how to pass the player a particular song corresponding to the row in which the button was pressed.
For instance: if I have two rows and #1 says Jay Z and #2 says Red Hot Chili Peppers, I want to press the button in #1 to play Jay and to press the button in #2 for the Peppers. Simple. My code is flawed and no matter which row's button I press I can only get the same song to play.
I know why that's happening, but I don't know how to solve it. I'm just wondering if anyone could hit me with a few lines that could point me in the right direction.
I can't use didSelectRowAtIndexPath because I want something else to happen when the row itself is selected.
Will I need to create a method for this or is there something I've overlooked?
Thanks!
You could also set the tag property of each button you create during tableView: cellForRowAtIndexPath:, then when your buttonTapped event is called, look up the sender and find its tag. The tag property of UIView was provided for just this sort of problem.
If you need more information than that, you could create a UIButton subclass that stores any or all information needed about the associated song. Once again, you set that information during cellForRowAtIndexPath, to be retrieved when the button is tapped.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
// Dequeue a cell and set its usual properties.
// ...
UIButton *playButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[playButton addTarget:self action:#selector(playSelected:) forControlEvents:UIControlEventTouchUpInside];
// This assumes you only have one group of cells, so don't need to worry about the first index. If you have multiple groups, you'll need more sophisticated indexing to guarantee unique tag numbers.
[playButton setTag:[indexPath indexAtPosition:1]];
// ...
// Also need to set the size and other formatting on the play button, then make it the cell's accessoryView.
// For more efficiency, don't create a new play button if you dequeued a cell containing one - just set its tag appropriately.
}
- (void) playSelected:(id) sender;
{
NSLog(#"Play song number %d", [sender tag]);
}
Something like
- (void)buttonTapped:(UIView *)sender;
{
CGPoint pointInTableView = [sender convertPoint:sender.bounds.origin toView:self.tableView];
NSIndexPath *tappedRow = [self.tableView indexPathForRowAtPoint:pointInTableView];
// get song that should be played with indexPath and play it
}
something like in tableView: cellForRowAtIndexPath: give your button tag as index.row and bind the function below to button's touchup inside event
-(void)button_click:(UIView*)sender
{
NSInteger *index = sender.tag;
//play song on that index
}
I think this will help you!

Changing an Object in UITableViewCell is also changing the Object of a reused UITableViewCell

Code updated to working version. Thanks again for the help :)
Hey guys. I have a UITableViewController set up to use a custom cell loaded from a nib. Here's my cellForRowAtIndexPath:
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellIdentifier = #"PeopleFilterTableViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"PeopleFilterTableViewCell" owner:self options:nil];
cell = peopleFilterTableViewCell;
self.peopleFilterTableViewCell = nil;
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
PeopleFilterTableViewCell* tableViewCell = (PeopleFilterTableViewCell *) cell;
/* Set direct button name */
Person* personAtRow = [directsToShow objectAtIndex:indexPath.row];
[tableViewCell.directButton setTitle:personAtRow.name forState:UIControlStateNormal];
/* Set direct head count */
tableViewCell.headcountLabel.text = [NSString stringWithFormat:#"%d", personAtRow.totalHeadCount];
UIImage* unselectedImage = [UIImage imageNamed:#"filterButton.png"];
UIImage* selectedImage = [UIImage imageNamed:#"filterButtonClosed.png"];
UIButton* newFilterButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
/* Set filter button image */
if(personAtRow.filtered){
[newFilterButton setSelected:YES];
} else {
[newFilterButton setSelected:NO];
}
tableViewCell.filterButton = newFilterButton;
return cell;
}
This seems to work fine for me, but one issue has come up with the code after the /* set filter button image */ comment.
The filter button is a UIButton in my custom cell nib that is supposed to reflect the state of a model array containing 'Person' objects, which have a field that can be toggled to represent whether they are being filtered or not.
The way that I allow a user to update this model object is through a custom delegate method on my top level controller, which, whenever the user clicks the filter button, updates the model and the state of the button, and additionally updates a mapViewController with some data to show based on the state of the model:
- (void)updateViews:(id)sender {
UIImage* unselectedImage = [UIImage imageNamed:#"filterButton.png"];
UIImage* selectedImage = [UIImage imageNamed:#"filterButtonClosed.png"];
int row = [self rowOfCellSubView:sender];
Person* personToFilter = [self.directsToBeShown objectAtIndex:row];
NSLog(#"Filtering person with corpId: %#, name: %#", personToFilter.corpId, personToFilter.name);
if (personToFilter.filtered){
//update button image
[sender setImage:unselectedImage forState:UIControlStateNormal];
[sender setSelected:NO];
//add person back.
Person* directFiltered = [self.directsToBeShown objectAtIndex:row];
directFiltered.filtered = NO;
NSLog(#"Filtering person with corpId: %#, name: %#, filtered: %d", directFiltered.corpId, directFiltered.name, directFiltered.filtered);
} else {
//update button image
[sender setImage:selectedImage forState:UIControlStateSelected];
[sender setSelected:YES];
//remove person.
personToFilter.filtered = YES;
NSLog(#"Filtering person with corpId: %#, name: %#, filtered: %d", personToFilter.corpId, personToFilter.name, personToFilter.filtered);
}
[self updateSitesToShow];
[self.mapViewController performSelectorOnMainThread:#selector(updateDisplay) withObject:nil waitUntilDone:NO];
}
My issue comes with the updating of the state for the filter button. When my app loads the tableview, everything looks fine. When I click a filter button in a certain cell row the state of the button updates correctly, and my model objects are also updating correctly since I see the expected behavior from the mapView which I'm ultimately updating.
However, the issue is that when I click on the filterButton in one cell row and then scroll down a few rows, I notice another filter button in a different cell now has the same state as the one I clicked a few rows above. If I scroll back up again, the original button I clicked 'on' now seems to be 'off' but the row below it now appears 'on'. Of course all this is affecting is the actual display of the buttons. The actual state of the buttons is consistent and working correctly.
I know this issue must have something to do with the fact that my cells are being reused, and I'm guessing somehow the same buttons are being referenced for different cell rows. I'm at a loss as to how this is happening though, since I'm creating a new filter button for each cell, whether the cell is reused or not, and resetting the filterButton property of the cell to be the newly created object. Notice for example that the text of the headCount property, which is a UILabel also defined in the cell nib, is also being reassigned to a new String object for each cell, and it is displaying correctly for each row.
I've been struggling with this problem for a few days now. Any help or suggestions at all would be really appreciated.
Table views cache their cells to allow you to reuse them, which you're doing whenever you call dequeueReusableCellWithIdentifier:. You should call setSelected: before the end of your tableView:cellForRowAtIndexPath: method to synchronize the state of the button with the state of the Person instance that corresponds to the current row.
Another thing to consider is that creating new button instances each time you return a cell is pretty wasteful. Consider creating and configuring the buttons (setting titles, images, etc.) once per cell instance inside the if block where you're loading the cell from the nib file.
This is a typical issue that happens when you change the cell view structure after it has been dequeued, while you're allowed to change the cell structure only in the alloc/init stage. After dequeue or alloc/init you are allowed to customize the content only and not the structure.
In your case, when the cell (let's say it is row-0) is loaded from the nib, the internal subviews structure is created (as defined in the Nib) and filterButton instance is assigned to one of these subviews. But a few lines below you create a new UIButton and replace the filterButton instance with this new one, but the real button subview will remain the same! Now when you click a button, of course the "real" button (that is the button in the cell view hierarchy which has been originally created by the Nib) will be triggered, the callback called and the state changed.
Later, when you scroll up this row-0 cell, it is removed from screen and enqued and then re-used for another cell, let's say row-9. At this point, former cell row-0 is going to be reused for cell row-9, but setting filterButton has still no effect, as you're keep going using the original button loaded initially by the Nib for cell row-0. Of course you will see these buttons states to be messed during scrollings as they are reused by the queue mechanism differently each time (so row-0 --> row-9, later row-0 --> row-8 and so on).
The solution is simply to change the button status: [self.filterButton setSelected:NO|YES] and not change the cell view content.
So the golden rule is: NEVER change the cell structure after you've dequed it. If you need to change the structure then use DIFFERENT cell IDs. Of course the more customizable is the cell the easier is the possibility to reuse them.

Is there a way to change sectioned tableview to drilldown tableview?

I have a sectioned tableview with a plist wich is an array filled with dictionaries.
In my app all sections and cells are shown on the first view.
But now I need to change it to look like this: sections have to become cells(with names of sections). When you press this cell the cells contained in section have appear.
Is there a way to do it without too much rewriting the code?
Thanks and sorry for the noob question :o)
I understand, that you still want to use one tableview, where cells are hidden for all sections except one. In that case you can do this:
Implement -tableView:headerForSection: and place a button on the view that you will return. Write the sections number on the buttons tag. Add an action to the button with parameter (UIButton *)sender: `-(void) headerPressed:(UIButton *)sender
You need to implement -tableView:heightforHeaderInSection: as-well.
-(void) headerPressed:(UIButton *)sender writes the senders tag to a member integer and reloads the tableview.
in -tableview:numberOfRowsInSection: you return 0 if the sections int is not equal to the member integer you saved. If it is equal, return the number of rows in that section.
You will need to create two table view classes. One for the one that holds the section names, and the other that holds the rows of each section. In the first one, retrieve the section names from the plist and populate the rows in the table accordingly. Then in the - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method you need to push another view controller onto the navigation stack(something like this-provided in the template code):
// Navigation logic may go here. Create and push another view controller.
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
Then for the other table view class you populate it by reading in the info from the plist that corresponds to the tapped section. Hope this helps.