I'm building a blog reader app with a list of post objects in an NSArray.
cell.postTitle.text=post.Title;
I'm trying to find out which post has been selected and then set the corresponding cell.postTitle.text to a lighter font.
Somehow I have to remember this state when the navigationcontroller segue back to the top level (and destroyed?).
Can anyone tell me the best way to do this? Each post object has a postID. Maybe I can store this in NSUserDefault, but the list of read postID might grow too big over time.
Also there is didSelectRowAtIndexPath but in this method, I can't access the cell properties directly right?
If you are using a UITableView to display your information you should use the delgate didSelectRowAtIndexPath.
In order to make this work with a custom interface (I assume you have), you should create your own custom cell, subclass UITableViewCell and create a controller and xib. You can then register your xib to the table and use that. Then you can call the needed attributes.
Somehow I have to remember this state when the navigationcontroller segue back to the top level (and destroyed?).
This is best handled by using a delegate method by creating a custom protocol:
https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html
When your user clicks the cell, you would call a delegate method which could set the postID value back in the top controller.
Also there is didSelectRowAtIndexPath but in this method, I can't access the cell properties directly right?
Yes, you can get at the cell. Check out this question and answer:
How to reach the current selected cell in didSelectRowAtIndexPath?
Alternatively, if you want to get at the data you used to create the table cells in the first place, in your didSelectRowAtIndexPath method you can used the indexPath.row value to get the value from your array that is at that index position and pass that via a delegate method.
Found a solution.
Just add the postId of the selected post to an NSMutableArray in didSelectRowAtIndexPath. Then in cellForRowAtIndexPath, I check to make sure that the postID doesn't exist in my self.readPostID array.
If it does I set the font to Helvetica Light, else set it to Helvetica Bold.
First I had to make sure to [self.tableview reloadData] every time viewdidappear.
Second, I just save my NSMutableArray of readPostId to NSUserDefault everytime viewDidDisappear and reload the array in viewDidLoad.
Also I had to make sure that cell reuse doesn't affect the font. The else condition fixed that.
Related
I have another question open where I'm trying to figure out how to reload the collectionView without auto-scrolling. I was also realizing there are a lot of other situations where I will need to change things in the collection view. Also I have some items that I will want to change the .alpha on and change the text of. Is there a way to do all of this in Swift? For example (to be specific) if I have a collection view with a view in each cell and that view has a textField in it, can I change the alpha and text, (change alpha with animation even) without reloading entire table?
Look at the documentation for UICollectionView. There are several "reload" methods:
reloadData()
reloadSections(_:)
reloadItems(at:)
If you just want to reload a single item, update your data source's data and then call reloadItems(at:) passing in the index path for the item.
Another option, if a cell is currently visible, is to use the cellForItem(at:) method to get a reference to an existing cell. Then you can directly access UI components of the cell as needed. You should also update your data model as needed so if the user scrolls and comes back, the cell will be rendered properly.
Most appropriate where you can update your custom view of a particular UIcollectionViewcell is reloadItemsAtIndexPaths.
You would be handling a particular item than whole collectionview with reloadData.
You can handle it via notifications or some call backs in your code where you can make decision when to update which cell.
Hope it will help you.
I have a tableview that is based on a array of DB results, these results contains a date field. I have a custom cell that contains an image and labels. I'm trying to do:
At cellForRowAtIndexPath I verify if the date of current item (objectAtIndex:indexPath.row) has date field bigger than the last item (objectAtIndex:indexPath.row-1). If this is true: I want to add a cell filling the ImageView with a certain image, but I need to add a new row just for show this image.
How can I do this? I'm already doing this verification, but I need to add a new cell...
Do not use the cellForRowAtIndexPath to decide how many cells you want to have. At the point this method is called you should have already setup the data source to provide table view with all information needed.
Here is what you need to do. Refactor your code in a way so you:
Setup the data source first.
Force reload of the table view either by calling the reloadData method.
hey you can add the object in your data base(for example ns array) and refresh the table view with method
[tableView reloadData];
then the method cell for row at index path will be called again and it will refresh the table view's items.just make sure the method cellforrawantindexpath in your code knows to handle the new data type(make validations).
Your tableView data source should not contain any of that logic where the content of once cell depends on the content of another cell. Instead, you should have a data item for each requested indexPath and that data item should contain ALL logic necessary for the cell to be configured. If an action on that cell has an effect on how another cell should look, you apply a change to the corresponding data-item, and then call reloadRowsAtIndexPaths: for the indexPaths.
In short: configure cells ONLY in tableView:cellForRowAtIndexPath: or tableView:willDisplayCellAtIndexPath, and ONLY do configuring. Other logic should be placed in some data(-controller) object.
As suggested, you should add an item to your data-array. Then call -insertRowAtIndexPath: on the tableView. ReloadData is like a big ugly hammer that you only use when ALL of the data for that tableView changes.
I have a tableview with custom cells. Each cell contains a button you press, that prompts an alert.
The alert uses the UIAlertView delegate as expected, and it checks the title of the button to determine what the user pressed. This in turn calls a web service that submits data. Once that submission completes, I need to have the button in that cell change to another button image.
Reloading the data so that it reflects the updates sent to the server and then reloading the tableview is having no effect.
Is there a way to access the cell outside of the cellForRowAtIndexPath? I have it setting a global variable named selectedIndex based on what button I press, but that is as far as I can get. Is it even plausible (or a good idea) to access a cell this way.
Thanks for any help!
There are quite a few ways to reload the data in a tableview. But for your case, if you can get a reference to the cell, it would suffice to do little UI related changes(changing images or something like that).
If you think your table's content size is going to vary after the web service returns response, then you must reload the table. Ofcourse you can reload the whole table's content, or just a few rows or sections. Check out the official documentations for the detailed information on them
The global variable is not a good way to get the index of the cell, of which button is pressed. A better approach would be if you use the tag property of the button. Set the tag of the button with the row(or section whatever your schema is) of indexPath. Then you can fetch the tag in your button's selector method.
Get a reference to the cell when the web service call finishes, get an instance of NSIndexPath via indexPathForRow:inSection:.
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:button.tag inSection:0];
Check if the cell is still visible and go forward with that.
MyCustomCell *cell = (MyCustomCell *)[self.tblView cellForRowAtIndexPath:indexPath];
and do your changes on that cell there.
UITableView has a method (not the delegate method) called -cellForRowAtIndexPath:. Provided that cell is still visible, and you have stored the index path off, you can use that to obtain the cell. It will return nil if the cell is not visible (but in that case the delegate method will be called later on to provide a cell for that index path again before it becomes visible, so you would configure it then).
The caveats are that a web services call is presumably asynchronous, and lots of things can change between when the user presses the button and you get the web response. The user could have scrolled the cell offscreen such that it is no longer visible, in which case you would need to store off the updated value somehow so you can properly configure the cell later on. Also, if your code calls reloadData for any reason, even keeping the NSIndexPath may not make any sense -- if your underlying model has changed at all, the model record associated with the user's click may now be at a completely different NSIndexPath (or may not exist in the data set at all). Depending on your situation those may or may not be issues, but if they are, it may be best to keep a reference to the selected record (or the primary key of that record), and when the call comes back, determine what the index path to that record now is, and see if the cell for that index path is visible.
Lastly, I'd recommend using properties of your view controller to store off these values, not globals. If you ever create a new instance of the view controller, and you change behavior based on the value of the global variable, it may still be set (with completely bogus values) from the previous usage of that view controller class.
I have a TableView with a prototype cell, in this prototype cell I have a text field.
Well, what I need is to get a information from this text field when it changes. I need to do that to feed a object.
How can I do that ?
Short answer - you don't.
Slightly more in depth answer...
The UITableViewCell is a "view". It is used only to display information to the screen. It is not for storing data in.
In a UITableViewController (i.e. UITableViewDatasource and UITableViewDelegate) you should have an NSArray (or an NSFetchedResultsController) that you use to store information in.
Then using the delegate methods you populate the table with that data.
If the data changes then you reload the table to update the cells.
What should never happen is the following...
Load the table by passing in data to the cell.
The cell then changes its own data and changes what is on the screen.
The controller then reads that data out of the cell.
No, no, no, don't do this.
What should happen is this...
Load the table and configure the cell display to represent the correct part of the data.
When the button is pressed (or text field is changed, etc...) in the cell then call a method back in the controller to update the data accordingly.
Now the data has changed, reload the cell.
It will now show the correct information based on the new data.
You need a custom cell with a public property (IBOutlet) UITextfield. Then you can set your ViewController as the textField's delegate in cellForRowAtIndexPath,
cell.textField.delegate = self;
in this case your ViewController has to implement UITextFieldDelegate protocol.
I am building a simple app with a table view filled with custom view cells and using a storyboard. I want to add a actions on the cell each time the user tap it.
So far, I tried to create an IBOutle to link my cell to my tableViewController and add the action manually in the code but each time I try to do it I get an error message saying "Illegal Configuration - cannot have a prototype object as its destination".
The only quick fix I found is to add a UIButton with a transparent background and no title which fills in the whole cell and attached the action to it.
Is there any more elegant way to do it?
Not only is there a more "elegant" solution, but there is also a correct way to do this.You should be using the didSelectRowAtIndexPath method for your cells.
You should read what the Apple Docs have to say
And also, here is a tutorial on how to use row selection in your tableView.
The elegant solution is to use your table view's delegate method tableView:didSelectRowAtIndexPath: and put all your action code there.