I have created StoryBoard segue application containing 1st CategoryViewController and 2nd CheckListTableController. Category(buttons) wise I am opening different question list on tableview of CheckListTableController.
I have set check and uncheck button and its respective colour in tableView cell. I have taken NSMutableArray and adding indexPath to this to set the particular colour to cell.
When I am navigating between these controller I want my tableView cell colour should be reserve.
Any Idea how to do this. Thanks in advance.
Edited with query 26Aug13
Now I need same functionality by using plist file or Core data. So that user can save sessions of task and access it later. Eg. in session one he did check uncheck mark for ABC building then session saved. Session two again he did check/unchk activity for different location XYZ building then saved.
Which method would be suitable here. Plist file or Core data? Can you redirect me to specific solution.
Edit with some Code
Catergory_ViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"chkListTable"])
{
NSString *bldgArrayString = [[NSString alloc] initWithFormat:#"bldg"];
checkListTableViewController *chk= segue.destinationViewController;
chk.gotquestArrayString = bldgArrayString;
}
}
checkListTableViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
if ([gotquestArrayString isEqual:#"bldg"])
{
buildingQuest = [[NSMutableArray alloc]initWithObjects:#"Motor vehicles are not parked in the space",
#"Lightning protection system (Electronic)",
#"Lightning protection systems available on all buildings",
#"Reception facilities in order and not damaged",
}
}
//tableView button method where indexPath added to MutableArray
-(void)yesAction:(id)sender
{
arrayCheckUnchek = [[NSMutableArray alloc]init];
UIButton *button = (UIButton *)sender;
UITableViewCell *cell = (UITableViewCell *)button.superview.superview;
UITableView *curTableView = (UITableView *)cell.superview;
NSIndexPath *indexPath = [curTableView indexPathForCell:cell];
cell.backgroundColor = [UIColor greenColor];
[arrayCheckUnchek addObject:indexPath];
}
- (void)tableView: (UITableView*)tableView
willDisplayCell: (UITableViewCell*)cell
forRowAtIndexPath: (NSIndexPath*)indexPath
{
// UITableViewCell *Cell = [myChklist cellForRowAtIndexPath:indexPath];
if ([arrayCheckUnchek containsObject:indexPath])
{
cell.backgroundColor = [UIColor greenColor];
}
}
1.you need to save your NSMutable Array in Plist file or in UserDefaluts whenever you have changed the selection(checked/ unchecked) at that time you should update your Plist or userdefaluts
2.Read your plist file in ViewWillApper method in your tableviewcontroller. and pass this data to your "arraycheckuncheck"
hope it will work for you
happy icoding ....
NSAnant
Related
I have created a View Controller with a Navigation bar and UiCollectionView. UI Collection View contains custom UICollectionViewCell. Navigation bar contains two UIBarButton items, one is on the left corner - prepared segue to previous page and other item is on the right corner - arranged to delete cell(s) in the UI CollectionView as show in the picture below:
Main Screen
Now I want to remove the selected UICollectionViewCell when UIBarButtonItem in the right corner, is tapped.
This how my cellForItemAtIndexPath method look like:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath{
self.GlobalIndexPath = indexPath;
MessagesCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"messagesCell" forIndexPath:indexPath];
cell.MessageHeading.text = [self.Message_Heading objectAtIndex:indexPath.row];
cell.MessageSubject.text = [self.Message_Subject objectAtIndex:indexPath.row];
cell.MessageContent.text = [self.Message_Details objectAtIndex:indexPath.row];
[cell.Checkbox setHidden:YES];
[cell.Checkbox setChecked:NO];
}
I have tried a solution like Declaring Indexpath as global variable and use it in the button event as below:
#property (strong,nonatomic) NSIndexPath *GlobalIndexPath;
some other code .......
//When Bin Icon(UIBarButtonItem) Clicked
- (IBAction)DeleteMessages:(id)sender {
[self.view makeToast:#"You clicked delete button !"];
NSIndexPath *indexPath = [self.MessageCollectionView.indexPathsForVisibleItems objectAtIndex:0] ;
BOOL created = YES;
// how to get desired selected cell here to delete
MessagesCollectionViewCell *cell = [self.MessageCollectionView cellForItemAtIndexPath:self.GlobalIndexPath];
if([cell.Checkbox isHidden])
{
[cell setHidden:YES];
}
else{
[cell.Checkbox setChecked:NO];
[cell.Checkbox setHidden:YES];
}
}
It's not worked.
For showing the UICollectionViewCell selected as checked, i'm using #Chris Chris Vasselli's solution
Please help me with this. Thanks in Advance.
There are a few steps. First, determine the selected indexPath, but don't assume there is a selection when the method is run....
// in your button method
NSArray *selection = [self.MessageCollectionView indexPathsForSelectedItems];
if (selection.count) {
NSIndexPath *indexPath = selection[0];
[self removeItemAtIndexPath:indexPath];
}
There are two more steps to remove items from a collection view: remove them from your datasource, and tell the view it has changed.
- (void)removeItemAtIndexPath:(NSIndexPath *)indexPath {
// if your arrays are mutable...
[self.Message_Heading removeObjectAtIndex:indexPath.row];
// OR, if the arrays are immutable
NSMutableArray *tempMsgHeading = [self.Message_Heading mutableCopy];
[tempMsgHeading removeObjectAtIndex:indexPath.row];
self.Message_Heading = tempMsgHeading;
// ...
Do one or the other above for each datasource array. The last step is to inform the collection view that the datasource has changed, and it must update itself. There are a few ways to do this. The simplest is:
// ...
[self.MessageCollectionView reloadData];
OR, a little more elegantly:
[self.MessageCollectionView deleteItemsAtIndexPaths:#[indexPath]];
} // end of removeItemAtIndexPath
I know that dequeueReusableCellWithIdentifier:forIndexPath is called by tableView method inside the tableviewcontroller. And if I understand correctly, tableView method is called several times until all the cells are populated. But what I don't know is where do you get the value for the parameter IndexPath? I want to use dequeueReusableCellWithIdentifier:forIndexPath for a method that I created because I want to access my cell to copy some values of its properties.
NOTE:
I already populated my cell, which means that I successfully used the method tableView.
(Edit) ADDITIONAL INFO:
I'm trying to create a profile and edit profile tableviews. Inside the profile tableview, I displayed the name, address, contact#, etc., of the user. Also, I have a segue called edit profile. In the edit profile, I have textfields for each category (name, address, etc.). What I want to do is, if I edit the contents of the textfields, I should be able to display the new contents in my profile tableview. An example case would be: in the profile view I'm displaying -> name:human, address:earth (each in its own cell). Now if I go to editprofile tableview, I will edit the contents such that -> name:alien, address:mars. After that, there is a button called 'apply' to end editing of contents and go back to profile tableview. If I go back to profile view, the display should now be name:alien, address:mars and not name:human, address:earth.
Here is some code if it's any help. The code is called by a button in tableviewcontroller. "MyCell" is the class of my cell. This code is not working properly. I hope someone can help me fix this.
- (IBAction)updateCopies:(id)sender {
static NSString *ident = #"MyCell";
NSIndexPath *indexPath;
//create cell
MyCell *cell = [self.tableView dequeueReusableCellWithIdentifier:ident forIndexPath:indexPath];
//create variable for accessing cells
int row = [indexPath row];
_labelValues[row] = cell.textField.text
}
You should only use dequeueReusableCellWithIdentifier when you need to supply the table view with a cell to display. If you want to get the UITableViewCell object at a certain index, you should use cellForRowAtIndexPath.
Your problem
What you really need is a model class. You can then pass this to the edit controller, which changes the properties. Then when you return to the tableView, you can reload it and display the new properties.
What you could also do is create a delegate protocol for your edit profile controller, something like EditProfileViewControllerDelegate with something like:
protocol EditProfileViewControllerDelegate {
- (void)editProfileViewController:(EditProfileViewController *)controller didUpdateName:(NSString *)name address:(NSString *)address;
}
You can implement this delegate in your table view controller and use it to update the values when the text is changed. However, this quickly becomes unwieldy, I would not recommend it over using a proper model class.
You can get indexPath using CGPoint..You can use dequeueResusableCell for reusability of the cell..
- (IBAction)updateCopies:(id)sender {
CGPoint position = [sender convertPoint:CGPointZero
toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:position];
//create variable for accessing cells
MyCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
int row = [indexPath row];
_labelValues[row] = cell.textField.text
}
Hope it helps you..
Use this
- (IBAction)updateCopies:(id)sender {
MyCell *parentCell = (MyCell *)sender.superview;
while (![parentCell isKindOfClass:[MyCell class]]) { // iOS 7 onwards the table cell hierachy has changed.
parentCell = parentCell.superview;
}
UIView *parentView = parentCell.superview;
while (![parentView isKindOfClass:[UITableView class]]) { // iOS 7 onwards the table cell hierachy has changed.
parentView = parentView.superview;
}
UITableView *tableView = (UITableView *)parentView;
NSIndexPath *indexPath = [tableView indexPathForCell:(MyCell *)parentCell];
NSLog(#"indexPath = %#", indexPath);
}
Well I got what you want to accomplish.
Firstly, there is a delegate which is being called when you click/select a cell and go to the Edit Profile page. That delegate is
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
///
}
Make a global variable, say selectedIndexPath which holds the current cell index path which is being edited. Update this value each time when you go to edit profile page.
Like this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
selectedIndexPath = indexPath;
// code to go to edit page...
}
Now in your updateCopies Method, do like this
- (IBAction)updateCopies:(id)sender {
//get the existing cell with the indexPath
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:#[selectedIndexPath]];
[self.tableView endUpdates];
//rest of your code goes here...
}
I am having trouble figuring out how to get the indexPath for the selected row by pressing a button inside a custom UITableViewCell.
I have in my cellForRowAtIndexPath:
self.rCell.reportUserButton.tag = indexPath.row;
and in my prepareForSegue:
ReportUserViewController *reportUserVC = segue.destinationViewController;
reportUserVC.message = [self.receivedMessages objectAtIndex:self.rCell.reportUserButton.tag];
here is my issue...
self.rCell.reportUserButton.tag is set to the value of the last cell in view.
If I want the first cell, the last cell is always being set.
How do I get the indexPath for the cell that has the active Report User button????
cellForRowAtIndexPath call when cell created and reused in table view, you assign value like below code means only last reused cell indexPath assigned to your cell.
self.rCell.reportUserButton.tag = indexPath.row;
Use delegate in cell to pass values
// In CustomCell Class
#protocol yourdelegate <NSObject>
-(void)passCellIndexAction:(CustomCell *)cell;
#end
-(void)buttonClickAction
{
[delegate passCellIndexAction: self];
}
// In View controller class
-(void)passCellIndexAction:(CustomCell *)cell
{
ReportUserViewController *reportUserVC = segue.destinationViewController;
reportUserVC.message = [self.receivedMessages objectAtIndexcell.reportUserButton.tag];
}
There is another way of doing it:
- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point
For example if using a custom Details button and a segue from that button to a details view:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"news-detail"]){
NSIndexPath *indexPath = [self.myTableView indexPathForRowAtPoint: ((UIButton *)sender).superview.superview.center];
NSArray *keys = [self.dataSource allKeys];
NSDictionary *newsItem = [[self.dataSource objectForKey:[keys objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row]; ;
[(MyDetail_ViewController *) segue.destinationViewController setDataItem:newsItem];
}
}
You should use the delegate method on click of your cell button to tell it about the tableViewController.
#protocol cellDelegate <NSObject>
-(void)calledOnButtonClick:(CustomCell *)cell;
#end
Then on button Click event of your cell call the delegate like
if ([delegate respondsToSelector:#selector(calledOnButtonClick:)])
{
[delegate calledOnButtonClick:self];
}
Now at your tableViewController
-(void)calledOnButtonClick:(CustomCell *)cell
{
NSIndexPath *iPath = [_tableView indexPathForCell:cell];
}
it will give you the correct index path
I have two table views, one called mainTableViewController (mtvc), the other called detailTableViewController (dtvc). It's very typical click the accessory button on the main tableview cell bring you to the detail tableview kinda thing.
In the prepareForSegue method, the data passed from the main tableview to detail tableview is a NSMutableArray called item.
And this is how I got it displayed: cell.detailTextLabel.text = self.item[indexPath.row];
The cool thing is I managed to do in-place editing on the detail table view cell (overwrote the NSTableViewCell, added a UITextField as subview to each cell).
everything works, the last thing I spent whole day cannot figure out is how do I update the NSMutableArray item after in-place editing taken place, the ultimate goal is in-place editing, and the main tableview data shall reflect the change.
I tried to use delegation and protocol but it does not work (the in-place edited content didn't got passed back, part of the reason is I don't know how to capture the edited content, it's not like it's a text field with a name, I can't just do updatedContent = self.myTextField.text to grab the change)
I'm running out of ideas, any help would be highly appreciated, thanks.
Here's the prepareForSegue in the main tableview controller
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"toInventoryDetail"]) {
NSMutableArray *selectedItem = nil;
if (self.searchDisplayController.active) {
selectedItem = _searchResults[[sender row]];
} else {
selectedItem = _appDelegate.items[[sender row]];
}
UPFInventoryDetailTableViewController *idtvc = segue.destinationViewController;
idtvc.item = selectedItem;
}
}
and here's the cellForRowAtIndex at the detail tableview controller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UPFEditableUITableViewCell *cell = [[UPFEditableUITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier];
cell.textLabel.text = _appDelegate.title[indexPath.row];
cell.detailTextLabel.text = self.item[indexPath.row];
[cell showEditingField:YES];
return cell;
}
I wrote the delegation but delete them after cause they didn't work.
I had an idea, still using delegation and protocol obviously: when the 'done' button in the detail tableview hit, I go grab all the row contents and build a new array, using delegation to pass this new array back to the main tableview controller, add this new array into the model meanwhile delete the old one. The tricky thing is still HOW CAN I GRAB ALL THE CONTENTS in the detail tableview?
update:
Haha! I think solved half of the puzzle !
here's the solution for the detail tableview controller
- (IBAction)doneUpdate:(UIBarButtonItem *)sender {
[self.delegate addItem:[self newItem]];
}
- (NSMutableArray *)saveItem
{
NSMutableArray *newItem = [[NSMutableArray alloc] init];
NSArray *indexPathes = [self.tableView indexPathsForVisibleRows];
for (NSIndexPath *indexPath in indexPathes) {
UPFEditableUITableViewCell *cell = (UPFEditableUITableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
[newItem addObject:cell.editField.text];
}
return newItem;
}
and here's the main tableview controller
- (void)addItem:(NSArray *)item
{
//take the updated item then insert the items array as new item
[_appDelegate.items addObject:item];
//remove the selected item (the one being updated) from the items array
[_appDelegate.items removeObject:_appDelegate.selectedItem];
[self.tableView reloadData];
[self.navigationController popViewControllerAnimated:YES];
}
When you creating a cell - give tags to your UITextFields
You can collect data entered by its delegate methods - you can either make NSDictionary/ key value pairs or you can add it to NSArray.
- (void)textFieldDidEndEditing:(UITextField *)textField {
if(textField.tag == 11) {
// you can add it to your desired array/dictionary
}
}
OR
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if(textField.tag == 11) {
// you can add it to your desired array/dictionary
}
}
You can use Delegation/Protocol or store this values in NSUserDefault and get it back on mainViewController.
Do you have a separate data model class(classes) for your selectedItem? That would be the appropriate way to persist data between the two TableViewControllers. It can be Core Data or simply a NSMutableArray that lives in memory. The DetailViewController updates the item and saves the changes, then the mainTableViewController reloads the TableView (or even just the data backing the previously edited cell.
Perhaps even consider the Model-View-Controller-Store pattern promoted by BigNerdRanch.
i have a TableView with a Custom Cell and a Section Header. The Header shows me the Country and the custom Cell shows me the City.
which look like this:
USA
New York
Los Angeles
Germany
Berlin
Frakfurt
every Cell got a Button. after a press it will navigate and push the city name to the detail view .
The Problem is, that i don't know how to determine the city name after i pressed the button.
I had a solution but it doesn't work anymore:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
StandortCell *cell = (StandortCell *)[tableView dequeueReusableCellWithIdentifier:#"ortCell"];
[cell.detailButton setTag:indexPath.row];
cell.ortLabel.text = [managedObject valueForKey:#"stadtname"];
}
- (IBAction)detailButton:(id)sender {
UIView *contentView = [sender superview];
UITableViewCell *cell = (UITableViewCell *)[contentView superview];
NSIndexPath *cellIndexPath = [self.tableView indexPathForCell:cell];
NSInteger section = cellIndexPath.section;
UIButton * myButton = sender;
int row=myButton.tag;
NSIndexPath * indexPath = [NSIndexPath indexPathForRow:row inSection:section];
StrasseViewController *detail = [self.storyboard instantiateViewControllerWithIdentifier:#"strasse"];
self.selectedStandort = [self.fetchedResultsController objectAtIndexPath:indexPath];
detail.currentStandort = self.selectedStandort;
[self.navigationController pushViewController:detail animated:YES];
}
when i use my old code it will just show the correct street row in the first section. it didn't detect the other sections(Countries);
When i choose the first city in the thirt section. it will display me the first city in the first section.
I hope you can help me.
use this I hope it will solve your purpose.
Create a button pressed method in your view controller
(IBAction)detailButton:(UIButton *)sender {
CustomUITableViewCellName *cell = (CustomUITableViewCellName *)[[sender superview]superview];
NSIndexPath *cellIndexPath = [YOUR_TABLE_NAME indexPathForCell:cell];
}
For ios 7 add another superview.
Now in this way you will get your IndexPath and you an get the current row by using
indexPath.row or indexPath.section.
You can get the title using sender.title property.
You can use this indexPath in your array to the required details.
You need to send row and section information seperately so make tag as
Tag= row*1000+section.
now from tag get section and row value using row= tag/1000
section =tag%1000
use this value to make correct index path or find some better then 2 mins solution to get that.
Caution its a workaround correct will be to
Subclass UIButton
Add a indexpath property int it
make your class to make button object and insted of tag set indexpath property.
in CustomButton.h
#interface CustomButton :UIButton
#property (nonatomic,assign)NSIndexPath *path;
#end
in CustomButton.m
#implementation CustomButton
#synthesize path;
#end
Use this custom button on your table view cell and instead of tag set path property