I have a query; I have a dynamically populated table which contains strings. It has a search function attached, how can I perform a segue depending on the selected string/cell?
Any help would be much appreciated! Thanks!
I had a similar problem some time ago and this piece of code really helped me out.
I am assuming that you have your search function fully functional.
It is all based around an else if statement.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellcontent = selectedCell.textLabel.text;
if ([cellcontent isEqualToString:"CellOne"]) [self performSegueWithIdentifier:#"CellOne" sender:self];
else if ([cellcontent isEqualToString:"CellTwo"]) [self performSegueWithIdentifier:#"CellTwo" sender:self];
}
}
You will probably notice that this only caters for segues from the search RESULTS table. You need a very similar piece of code for your none-results table. I'm sure you can figure that little change out.
Let me know if you need any further information.
Implement the appropriate delegate method and assert the cell's textLabel text. Perform the appropriate segue...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
if ([cell.textLabel.text isEqualToString:#"SomeText"]) {
[self performSegueWithIdentifier:#"MySegue" sender:cell];
}
}
Related
I have a scenario where upon selecting a UITableViewCell in didSelectRowAtIndexPath:, I need to load and get the information from a different UITableViewCell.
I'm registering and using two different xibs to be used as my tableViewCells to allow for some more customization.
- (void)viewDidLoad{
[super viewDidLoad];
self.TABLE_ROW_HEIGHT = 66;
self.tblView.delegate = self;
self.tblView.dataSource = self;
[self.tblView registerNib:[UINib nibWithNibName:#"BasicCell" bundle:nil] forCellReuseIdentifier:#"BasicCell"];
[self.tblView registerNib:[UINib nibWithNibName:#"DetailCell" bundle:nil] forCellReuseIdentifier:#"DetailCell"];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//Property of the view controller which is an IndexPath
self.selectedIndex = indexPath;
BasicModel *basicModel = [self.models objectAtIndex:indexPath.row];
[self.apiClient detailModelSearch:basicModel.id];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
if([self.selectedIndex isEqual:indexPath]){
return 400.0f;
}
return 66.0f;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
BasicModel *basicModel = [self.models objectAtIndex:indexPath.row];
UITableViewCell *tableCell = nil;
if([self.selectedIndex isEqual:indexPath]){
DetailCell *detailCell = [tableView dequeueReusableCellWithIdentifier:#"DetailCell"];
tableCell = detailCell;
}
else{
BasicCell *basicCell = [tableView dequeueReusableCellWithIdentifier:#"BasicCell"];
tableCell = basicCell;
}
return tableCell;
}
-(APIClient *)apiClient{
if(!_apiClient){
_apiClient = [APIClient new];
__weak ViewController *_self = self;
_apiClient.detailModelSearchFinished = ^(DetailModel *detailModel){
_self.detailModel = detailModel;
//Problem is here
DetailCell *cell = [_self.tblView cellForRowAtIndexPath:_self.selectedIndexPath;
dispatch_async(dispatch_get_main_queue(), ^{
[_self.tblView beginUpdates];
[_self.tblView endUpdates];
[_self.tblView reloadData];
});
};
}
return _apiClient;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.models.count;
}
The basic structure is as follows.
App load and loads all BasicModels into the the models array.
User selects a cell which prompts an API detail search request
When detail search request is finished, the callback returns a DetailModel
What should happen next is since I know the selected index path of the touched cell, I want to use the DetailCell instead of the BasicCell to present the detailedInformation that comes from the DetailModel. My problem is when I call
DetailCell *cell = [_self.tblView cellForRowAtIndexPath:_self.selectedIndexPath;
I always receive the BasicCell that does not have the detailed view components I need to bind the detailModel to.
BasicCell xib
Detail Cell Xib
Table View Normal:
Table View Expanded with detail Cel xib
Ok now is very clear.
I can think of two ways, one is if you don't care about fancy animations just remove the (basic) cell and insert a new (detail) cell at the same index path, only after tho you have updated the model as well and perform the eventual type checks.
Quick and dirty, if you want something more clean you may want to refactor the model objects using polimorfism or other suitable patterns.
Another way is to update directly the cell with the received data. You may apply some fancy animations but loosing possibly some performances advantages.
Pretty simple solution actually. Reload data must be called before I can grab the expanded cell. Simple as this:
[_self.tblView beginUpdates];
[_self.tblView endUpdates];
[_self.tblView reloadData];
DetailCell *expandedCell = (DetailCell *) [_self.tblView cellForRowAtIndexPath:_self.selectedIndex];
expandedCell.lblData.text = #"IT WORKS!";
});
I took approach of the UITableview to get cell click ExpandView. I want something like this to be implement.
So, UITableView would be best approach for this or suggest me any good way of implementing, also I am not able to get subview to adjust according to screenSize.
Could be there are another ways to accomplish this but this is how I am expand UITableViewCell on the fly. This could give the idea and you can implement your solution.
I keep row heights in my data model:
- (void)viewDidLoad {
[super viewDidLoad];
//Data source
datasource = [[NSMutableArray alloc] init];
NSMutableDictionary *aDicti = [[NSMutableDictionary alloc] init];
[aDicti setValue:#"a TEXT" forKey:#"text"];
[aDicti setValue:#(50) forKey:#"cellheight"]; // here
}
When selection changed, just updating related key in data source.
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView beginUpdates];
[[datasource objectAtIndex:indexPath.row] setObject:#(50) forKey:#"cellheight"];
[tableView endUpdates];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView beginUpdates];
[[datasource objectAtIndex:indexPath.row] setObject:#(200) forKey:#"cellheight"];
[tableView endUpdates];
}
Once [tableView endUpdates]; executed heightForRowAtIndexPath and numberOfRowsInSection delegate methods fired and automatically adjust cell height with the value from data source.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [[[datasource objectAtIndex:indexPath.row] objectForKey:#"cellheight"] intValue];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return datasource.count;
}
If you do not want to keep row height in your data source you can basically apply this.
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView beginUpdates];
[tableView endUpdates];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView beginUpdates];
[tableView endUpdates];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView.indexPathForSelectedRow.row == indexPath.row) {
return 100;
}
return 50;
}
That's call, accordion, this site having good examples (with demos) for it, here's the link.
Basically when you are working with TableView you should play with number of section headers and cells.
In case of using section headers you should set numberOfRowsInSection to 0 (roll up) to X when you want to expand it. After that call
tableView.reloadData
I implemented this behavior here, with animation, with different heights:
https://github.com/rudald/expandedTableViewIOSSwift/
There are numerous open source projects regarding this feature. I've downloaded a few projects and the most customizable and issue-less, for me, was SLExpandableTableView
SDNestedTable does exactly what you want.
The module concept is that of having all the default functionality of
a UITableView and its cells while at the same time adding for each
cell a child UITableView. Each cell (SDGroupCell) in the main
SDNestedTableViewController tableview acts as controller for its own
sub table. The state, population and behavior of the table and
subtable is instead mostly controlled by
SDNestedTableViewController.
If you’re looking for a straight forward easy-to-setup library for expandable views, HVTableView is your choice. It provides an acceptable performance which is sufficient for using in regular projects.
Here are tableView data source and delegate implementation, and I set the maximum selection is 5.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
...
if ([multiOptions count] > 5) {
[self tableView:tableView didDeselectRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selected = NO;
//show alert
}
...
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
...
[multiOptions removeObject:selectedOption];
...
}
but here comes a question, if the options exceed the limit, the first click on cell will work just fine. but second time click the cell will call
didDeselectRowAtIndexPath
again, that's not what i expected, and I tried
[tableView deselectRowAtIndexPath:indexPath animated:YES];
in didSelectRowAtIndexPath, it didn't work, can someone give me a hint, how to correct it? thanks.
You have to check this in tableView:willSelectRowAtIndexPath:
Have a look at the UITableView class reference
especially at the last sentence:
Return Value An index-path object that confirms or alters the selected
row. Return an NSIndexPath object other than indexPath if you want
another cell to be selected. Return nil if you don't want the row
selected.
So something like this will work within tableView:willSelectRowAtIndexPath::
if ([multiOptions count] > 5) return nil;
I am currently making a tableView for my app, and I've got my cells from a .plist file. However I want to be able to enter my second view controller no matter, what cell I click on, the difference should be that the UIText for my second viewController will depend on which cell I click.
So far, I have imagined something like;
if(tableview.tag == 1){
myUIText.text = #"a";
}else if(tableview.tag == 2){
myUIText.text = #"b";
etc.......
Will this work using the same view controller, same UIText? If not, then how?
And how can I set the tags for my array in my .plist file?
I would appreciate your answers
EDIT: Here is a sample of two methods;
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.items count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString * id = #"plistdata";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:id forIndexPath:indexPath];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:id];
}
cell.textLabel.text = self.items[indexPath.row];
return cell;
}
More information is certainly needed by I will make some assumptions on your code and see if it helps any. I assume the the text you want to send is the title of the cell the person clicked on. Now how you send that to the next VC will differ depending on if you are using a segue or not. If you are using a segue you can do something like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"mySegue"]) {
UITableViewCell *cell = (UITableViewCell *)sender;
UpcomingViewController *viewController = segue.destinationViewController;
viewController.textView.text = cell.chapterText;
}
}
However if you are using didSelectRowAtIndexPath then:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UpcomingViewController *viewController = [[UpcomingViewController alloc] init];
viewController.textView.text = self.arrayOfChapterText[indexPath.row];
[self.navigationController pushViewController:viewController animated:YES];
}
Now again because your question wasn't very clear on your scenarios I have taken some liberties with what I think you are probably trying to do. I assume that the view controller that will show after you choose an item will have the UITextView as a public property so that you can set it before pushing or segueing to your new view. I also assume in the didSelectRowAtIndexPath that you are using a UINavigationController.
Hope this helps.
On my UITableViewI am using custom UITableViewCells. Each of these cells has a number of labels. When the user selects a cell, I need to capture the contents of just one of these labels, but I don't know how to do that. Here is my code. The line that I am using to attempt to get this label text is basically pseudo-code that clearly won't compile. Can somebody please tell me what I need to do here? Thanks!
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
Groups *group = [self.fetchedObjects objectAtIndex:indexPath.row];
cell.groupDescriptionLabel.text = group.group_descr;
cell.groupIDLabel.text = [group.group_id stringValue];
return cell;
}
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// capture the user selection
Groups *group = [self.fetchedObjects objectAtIndex:indexPath.row];
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
NSString *selection = selectedCell.groupDescriptionLabel.text; //<-- pseudo-code
NSLog(#"%#", group.group_descr);
...
}
It's generally a bad idea to get data out of the view. You shouldn't really be using any view objects as a way of storing information.
You are already getting the string when you are in the cellForRowAtIndexPath method.
You should be able to do the same in didSelectRowAtIndexPath to get the same string.
That way you don't have to get the text out of the label at all.
Thanks
If you know that celForRowAtIndexPath is going to be returning one of your custom cell types instead of a generic UITableViewCell, cast the result to your custom cell class:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// capture the user selection
MyCellClass *selectedCell = (MyCellClass *) [tableView cellForRowAtIndexPath:indexPath];
NSString *selection = selectedCell.groupDescriptionLabel.text; //<-- pseudo-code
NSLog(#"%#", selection);
//...
}