In my app I am using scrollable segment controller on header view of tableview and put dynamic data in it.
When click on segment index path, the particular id is get. Match this id with other entity data base change table view data.
My problem is, I cannot use segment index path in cellForRowAtIndexPath.
I am using different methods for this but it not work.
Related
I have the following situation
A TableViewController (ExploreViewController) has custom cells - CategoryTableViewCell. Each cell has a collection view with UICollectionViewCells.
I would like the CategoryTableViewCell to contact the ExploreViewController when displaying the collection view cells to determine what data it needs to display. The data is dependent on the index path row of the table view cell and on the index of the collection view cell.
How can I accomplish this using delegates?
I wouldn't do it that way. I would pass the data each cell needs to it as a model object in the table view controller's cellForRow(at:) method. If a cell's data changes, pass it a new model object. Then the cell can use that model data to respond to data source calls from its child collection view.
If you are determined to use the delegate pattern, or something like it:
Let's call it a data source instead of a delegate. Design a CategoryTableViewCellDataSource protocol. When you create a CategoryTableViewCell, set the table view controller as its data source.
Have the cell ask it's data source for the data to display. The delegate protocol would use the cell's position to figure out it's index path, and then fetch the data from the model and return it. (You'd find the midpoint of the cell's content view, convert the point to the table view's coordinate system, and then use the table view's indexPathForRow(at:) method to figure out the index path.
I'd like to get every data that is within all cells in one tableview which is quite a long list.
I'm looking for an approach on how to retrieve everything including those hidden in view, which I know the views are reused. I think some of you might have experienced this problem before, what are your approach on this?
I've tried
let cells = self.tableView.visibleCells
then looping into every cell and saving each data to an array but it is not effective in getting those that aren't part of the view or hidden. Is there a way to get over this?
In cellForRowAtIndexPath, YOU are telling the table what is in each cell. So why would you turn around and ask the table what's in each cell? If the user puts "Hello" in your first cell, then scrolls the table enough to push that first cell out of view, then when the user scrolls back to the top, YOU are the one telling it to put "Hello" back in that first cell. YOU own the data source, not the table.
You need a data source. That can be "empty" at first, maybe an array of empty strings if that's what you want (each index in the array could map to a table row for example). But then, as the user interacts with the text fields in the cells, you need to update that data source with the text they entered.
You should use that data source as your source for the cellForRowAtIndex method. That way you can handle populating the cells when they are requested by the table, and you also know all the data when the user is done.
Why not just update the model each time the user taps a key when editing a textfield? You could create a protocol for that cell subclass and make your view controller the delegate for each cell. As long as cells are guaranteed to stay on the screen while you're typing (you'll get some weird behaviors if not) the cell can send a message to the view controller or whatever you hook it up to telling it what new value to store. Then everything is already stored for you when you need the full list, and you don't have to interact with the tableview.
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 am making an iPhone app.
In this application I have to make a look like below.
I am not allowed to use collection view.
I am using tableview, and custom cells. Which I am easily able to incorporate. Means taking 3 subviews in Custom cells. And making a look.
Here the problem is In a cell, how do I distinguish each object. so that I can call each object, to set an image on image view.
Is there any Object oriented mechanism to distinguish all 3 objects in a cell ?
Try to get the data as NSArray of NSDictionary containing an array of 3 objects that you want to display on cell.
Assign tag to UImageView in the custom cell.
In cellForRowAtIndexPath, get the 3 objects and apply image using switch case.
Well everything depends on how you get the data from the server
You can use outlet collections which will give you an array of UIImageView and you can assign different tags to the imageview so you can assign to them.
You can use these guides to understand how outlet collections works:
http://nshipster.com/ibaction-iboutlet-iboutletcollection/
http://useyourloaf.com/blog/interface-builder-outlet-collections/
All the standard procedures should work to achieve this but then it only depends on how nice you want to do this.
The straight forward procedure is to expose the outlets of the image views and labels in the cell and assign the correct values to those when dequeuing/creating table view cell.
The first upgrade would be to rather expose 3 setters on the cell to simply set your model to each of them which will then internally set the images and texts inside the cell.
The next thing you may do is to rather insert an array of objects (always sending up to 3 in your case) instead of having 3 setters.
At this point you may actually rather use a collection view INSIDE the cell and make the cell a data source for the collection view. But this is totally optional.
Now since you may still dislike the table view data source you may create another model which contains an array of objects (again up to 3 in your case) and make a system that will distribute your original array of objects into the array of these containers.
If then you need to handle buttons or other touch events they may be handled with collection view delegate or 3 buttons and in both cases I advise you to handle those in the cell and create a custom delegate for the cell which will report the event with the appropriate model.
This together generates the following:
When you receive the data call a container class to distribute your array of objects (into groups of 3) and assign it to your table view data source (view controller usually)
Number of rows is the same as number of containers in the array
Cell for row assigns the container with row index to the cell. It assigns self as a delegate
Cell internally handles the object distribution either via collection view, separated outlets or outlet collections.
Cell handles actions and reports them back to the delegate (- (void)myCell:(MyCell *)cell selectedItem:(MyObject *)item;)
The cell delegate can again handle what to do upon reported actions
Also if you want to avoid a collection view inside the cell you can create a custom view using xib so you do not copy the labels, image views and such. Then simply create 3 of these custom views inside the cell. Also by using inspectable and designable these views will be visible inside the storyboard.
First I'll say that a restriction against using UICollectionView is silly. Are you still targeting ios5?
I'd look at it like this.
make your own view class for the 'subcell' let's use this term for any single instance of the 3 views per cell. I'd subclass UIImageView, adding the label for the name down the bottom and a 'setSelected:' kind of method to highlight when selected via user interaction by drawing differently.
make a UITableViewCell subclass to host and layout up to three of these subcells. I say up to 3 because the last cell may contain 1 or 2 subcells and not 3 if the total people to represent is not divisible by three.
Selection Logic: You'll need to override 'setSelected:' because you want to deselect and select only subcells, you don't want the whole cell to highlight on selection, only a third of it.
You'll also want to implement touchesEnded: in this cell so that you can figure out which of the three subcells was last touched, and you'll need to be able to query or communicate this back to the controller, probably using delegation. If the cell can communicate back whether selection was in subcell 0,1 or 2 then this together with the UITableViewDelegate didSelectAtIndexPath should map to your model nicely - selectedPerson = myArrayOfPeople[ (indexPath.row * 3) + subcellIndex ]
You'll be able to decorate your cells in cellForRowAtIndexPath: in similar fashion..
personOne = model.arrayOfPeople[indexPath.row*3]
personTwo = model.arrayOfPeople[indexPath.row*3 +1 ]
personThree = model.arrayOfPeople[indexPath.row*3 + 2 ]
As the title describes, I've got a tableview inside each of my collection view cells. For me, it makes sense that the superview's controller should control the view, but since in this case each tableview contains different data, I have made each superview (collection view cell) the controller for its tableview. I hope that makes sense. I know making a view to also be a controller violates the MVC paradigm, but I'm not sure what the proper way is achieve MVC compliance in this case. I also need to send messages to the table view based on what happens in the CollectionViewController. Do I need to subclass UITableViewController and make a reference to it in my collectionviewcell.h file?
Sorry if that was confusing. Thanks for the help.
I think your instinct is correct that having a view object serve as a data source is a violation of MVC. I would suggest having the owning view controller either serve as the data source for all the table views, or set up a separate model object for each table view that serves up the cells for that table view.
If you use a single data source you'll have to have a switch statement that figures out which table view is asking and fills the cells with the appropriate data.
My gut would be to create a thin table view data source class who's only job is to serve up the cells for the table view inside a collection cell (and respond to the other collection view data source protocol methods). Use a custom subclass of UICollectionViewCell that has a strong property that points to the data source object. You could make your custom cell class create an empty data source object at init time and hook up it's outlet to the table view.
Then in your cellForItemAtIndexPath method, pass the appropriate data to the cell's data source object. If you reuse a cell, it would already have a data source object, so you'd just replace the data with new data and trigger the reloadData method.
Your controller object would mediate between the model and the view, like it should. It would set up the model data for each cell, and then the data source object for each cell would act as the model for that cells table view.
If you later come up with several different types of collection cells that display different data, using separate data source objects for each cell would keep the code simple. You'd just subclass your data source object based on the cell type.