Passing data between UICollectionViewCells - ios

I am using a UICollectionView, in which one UICollectionViewCell covers the entire screen. Inside my UICollectionViewCell, I give people the opportunity to add text (UILabel), images (UIImageView) and color (UIColor). Now when the user navigates to the next cell i want the color, labels and image views to be displayed exactly as they were added on the previous cell. The users also have the option to pinch and pan the labels and images. In short, how can i pass on data from one cell to another?

I see several ways how to do this depending on your realization:
use global properties/ivars to store the selected data from user input.
In either case you probably handle UITextFiledDelegate methods in your controller or extract the cell by indexPath and copy values from the current cell to the next one.
And when the user presses the "Continue" button you:
1) If you create all you collectionViewCells at once in cellForItemAtIndexPath, then you should only reload the necessary cell via - (void)reloadItemsAtIndexPaths:(NSArray *)indexPaths and set the values you have saved previously.
2) If you create cells but the next one is not ready (for instance you save the memory) - all almost the same - you add a new cell to the collectionView and read the data from your properties.
3) If you have not a "Continue" button or/and user can swipe the cell in every moment - so you can reload the cell in scrollViewDidScroll(or scrollViewWillBeginDragging) or extract the existent by indexPath and modify it without reloading.

Related

Avoid UITableViewCell updating content when scrolled

I've found some similar questions already on SO, but nothing that seems to address this specific problem.
I'm using a UITableView with around 25 dynamic cells. Each cells contains a hidden UIProgressView. When the user taps on the download button within the cell to download that item, the UIProgressView is displayed and it indicates the progress of the download.
I've achieved this by assigning a tag to each cell which is equivalent to its corresponding downloadItemID. Each instance of MyCell has its own progressBar property.
This works fine as long as the table view is not scrolled during the download. It works also when the user is downloading multiple items at the same time. The code looks like this:
UIProgressView *theProgressBar;
for (MyCell *cell in self.tableView.visibleCells)
{
if (cell.tag == downloadItemID) theProgressBar = cell.progressBar;
}
float progressPercentage = (float)completedResources / expectedResources;
[theProgressBar setProgress:progressPercentage animated:YES];
The problem is that when the user scrolls the table view, the cell and progress view are transferred to another cell. It's simple enough to reset and hide the progress view for the new cell, but when the original/downloading cell is scrolled back into view, no progress is visible.
I've tried caching active progress bars into a dictionary and reallocating them back to the original cell in cellForRowAtIndexPath, but this is giving me the same result: no visible progress after scrolling the cell off and on the screen. Even if I can get them to show up, I'm doubtful I can get this to work seamlessly by rolling my own caching method.
What I need is to keep cells in memory. But can I work around dequeueReusableCellWithIdentifier? This whole problem has arisen because I had to switch to a dynamic system of allocating the cells, but it is too dynamic. Can I create the cells dynamically, but keep them in memory all the time once created, or at least keep the ones that are currently downloading?
(I understand the reasons why cell reuse is the preferred way to go with table views.)
You are working against the framework. As vadian says in the comment, you need to separate the logic and state information from the cells and put them elsewhere.
Here is one way of doing it.
Create a class to hold each download state, like a download ongoing flag, download progress, title, URL, etc.
In your view controller, create and add all your download objects to an array when the view controller is created. The first object corresponds to the first row in the table.
Whenever you dequeue a cell, populate it with data from the array. The NSIndexPath row property serves as the index into the array.
All your updates (download progress) updates the download objects in the array, then update the cell content using the updated object. You can use UITableView cellForRowAtIndexPath to get the cell for a specific array index, if you get nil there is no need to update it.

UICollectionView showing selected cells

i have a tableview with form fields, and there is a row that use segue to call an UICollectionView, everything is works except that i can't keep the selected cells (the visual effect that i show when the cell is selected) after go back to the tableview.
I mean, i selected my UICollectionView cells, after that i go back to the form, but if i need to again to my UICollectionView Cells, to deselect o select more cells before submit the data, once the UICollectionView appear my previous selection are there (i print the array, and i see the values) but i cant see the effect that i did for selected cells.
How i can keep the effect for selected cells if I'm going back to select again o deselect cells?
One thing to realize is that this is not going to happen by itself. When you segue back to the table view and the form fields, the UICollectionView is completely destroyed. The next time you show the collection view, it is a new and different collection view.
So, if you want to maintain a knowledge of what the selection was in the collection view, you are going to have to maintain it yourself, deliberately, storing it somewhere when you know that the collection view is being destroyed.
That way, the next time you show your collection view, even though that will be a completely new and different collection view, you can pass the knowledge of what the selection was to that collection view as you create and show it. The user will have the illusion of "returning" to the collection view, in the same state, but in fact you will have saved and restored its state.
It is then just a matter of reflecting the selected state in the collection view's display of its items. To do that, you need to configure your model so that when cellForItemAtIndexPath: is called, each cell looks selected if that item is supposed to be selected.
Every time you use segue to call an UICollectionView a new instance of UICollectionView is created and hence states of selected cells doesn't get restored.
I believe u must have taken an array of index paths of selected indexes to show the visual changes in the cell.
Make your tableView class as delegate of UICollectionView. Using its delegate methods return the selected index array to tableView class .And before pushing to UICollectionView send the same array of index paths back to the UICollectionView. Hope it helps.. Happy Coding.. :)

Change another cell in dynamic prototype UITableView when a switch in one cell change

I used to use static UITableView but the table is too long and overflow the memory.
I switched a dynamic prototype UITableView with 1 type of cell, which has an UISwitch in it.
One of the cell, when turning on the switch, will turn off the switch of another cell. These cells have fixed index.
The IBAction method is in my UITableViewCell subclass and I don't want to add the UITableView as a property in my UITableViewCell.
How do I achieve the above effect?
I'm planing to use an id or similar to distinguish between the cells as each cell's switch has different effects, that doesn't solve the above requirement.
Thanks,
I would add a block property to your cell which you can use to notify your controller of changes in the switch. See my answer below to a question on this:
How can I get index path of cell on switch change event in section based table view
All your logic can now be implemented in the view controller.
You are best to create a data model in the view controller which the cells simply provide views and controls onto. When you flick one switch and the block fires, update the data model and simply reload the table. Any cells affected will show the new data model positions for their switches. Avoid using one cell to adjust another. Just update the model and reload the cells.

iOS: Adding row to tableview

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.

adding a control to a custom cell view

I am getting really frustrated trying to solve this problem i tried implementing it in many many ways but no solution. I have a UIStepper in a custom cell and i want to change a value on the cell. Everything works fine expect when i scroll around the tableView the values from the UIStepper changes from one cell to another. Please help here are my screen shoots.
Link to tableview implementation and link to cell implementation
You are trying to store the stepper value inside each individual cell. That's not going to work because cells are reused; the cell that you now see in row 2 may reappear in row 20 when the user scrolls.
That is why you must store the value for the stepper in the model (your data) on a row-by-row basis, so that you can set it freshly and correctly for that row every single time cellForRowAtIndexPath: is called.
This, in turn, means that as the user steps the stepper, its valueChanged is going to need to talk to the table view data source so that the model can be updated ("the stepper value for row 5 has just been changed to 3") and maintained in the model.

Resources