Create nested table view or separate page? - ios

I'm trying to create an options page for my iOS app. I have an array of categories like this:
var options = [
"Location",
"Calculation Method",
"Juristic Method",
"Manual Adjustment",
"Daylight Saving Time"
]
Then I am loading them up in my view controller like this:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return options.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .Default, reuseIdentifier: "Cell")
cell.textLabel?.text = options[indexPath.row]
return cell
}
This give me a single table view perfectly! Now I'm trying to handle the click of each row to bring up a list of options for that category. For example, the Location will have a switch to enable GPS or allow them to select their location drop downs or a map. Calculation Method will bring up a table view of check marks. Daylight Saving Time will bring up a single row with a switch.
My question is what is the best approach for all this? Should I create a dictionary of arrays to hold my options and reuse the table, or should I create a separate view for each category of options? I'm finding conflicting or outdated tutorials on this and I'm also having trouble converting examples from Objective-C. Any help or direction would be greatly appreciated!

I'd suggest creating separate views for each category of options. From your example above, you'd end up with 5 more view controllers: Location, Calculation Methods, Juristic Method, Manual Adjustment, and Daylight Saving Time. And then for your Calculation Methods, since it's a table view of check marks, I'd probably have an array that stores each option inside the CalculationMethodsViewController. Same for the others. If they need other data to display, put it in the new view controllers - not in your original view controller.

For your top level of categories, I'd suggest using the sections of a tableview to separate things. Then each row in a section would correspond to the detailed option.
To do this, you could have an array of 'categories' that are to keep the order of sections. This would match the options array you've defined in your question. Alongside this, I would put a Dictionary of sub-category options. For Locations it would look like this:
var options = [
"Location" : ["location-enable-gps", "location-choose-list", "location-choose-map"],
"Calculation Method": ...,
"..."
]
In the above Dictionary, the array values for Location are constants that I've defined. This is because you will be changing the behavior of each cell drastically. Enable GPS can just be a checkbox, Choosing from a list may be better to drilldown/modal (and when selected display selected location), choosing from map may also lend itself to a modal design ("Modal" is when a view controller pops up and then dismisses after an action).
Let me know if this all makes sense, it looks like your options will be very diverse, so unfortunately I don't think there is one method (drill down, collection view) that works best. That being said, its all up to you on how you want your users to experience your app.

Related

Drag & Drop entire section instead of single row in UITableView

I am using a UITableView to display a couple of sections which represent a to-do item, each with a couple of rows, which represent a smaller to-do item:
- Finish thesis
-- Interview representatives
-- Rewrite chapter 8
-- Create cover sheet
- Clean the house
-- Do the dishes
-- Mop living room
-- Clean windows in bathroom
I have successfully implemented a way to rearrange the rows by using the DragDelegate and DropDelegate of UITableView. I make sure everything is moveable (protocol canMoveRowAt returns true). To give you an idea of how I do this:
func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
let toDoName = toDoList[indexPath.section].toDoItem[indexPath.row].toDoName
let itemProvider = NSItemProvider(object: toDoName as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = item
return [dragItem]
}
In MoveRowAt() I make sure the data is changed accordingly, removing the data from the sourceIndexPath and inserting it in the destinationIndexPath. This works great.
However, I would like to make sections draggable as well - to sort the to do list on priority. For example, if I add a new to do item, it automatically is appended to the bottom, but maybe this is something important that needs to be done first, so I want it - as a section with all its rows - to be dragged up if needed.
Can I accomplish this with the same method? I have figured out that there are no protocols for sections as there are for rows (moveRowAt exists, but moveSectionAt does not, same for canMoveSectionAt).
I have found a function, tableView.moveSection(section, toSection: section), which I will probably need to use. But how would I implement the drag & drop and attach it to the header of the section? Do I need to use a custom UILongPressGestureRecognizer? Any tips or available libraries on how to accomplish this?
I don't know if it's possible to drag and drop an entire section, but probably not, right now the API can consents to drag and drop row; one thing you could do is to create a CollectionView with a tableView in every Item, so you can drag and drop the Item containing your tableView

Swift Button That Outputs UICollectionView Cells One by One?

I made a UICollectionView, and everything is working. It makes 100 cells that I can scroll through in simulator with no problem.
However, rather than seeing all the cells at once, I want the cells to be released one by one whenever that red button is pressed.
I am confused because I noticed in the storyboard, it hard codes the number of cells it has on the screen at once. Is there any way to get around this?
Thank you!
This is what the UI looks like in storyboard.
This is the code I used to make it. It's basic, and just says to fill the text box of the cell with a string from the array.
Your question is garbled.
A collection view has a delegate and a data source. The data source responds to messages in the UICollectionViewDataSource protocol. That protocol lets the collection view ask how many sections it has, and how many rows in each section, as well as asking for the cells from those sections and rows.
There are also methods that let you tell the table view that you want to add more cells. Take a look at the method insertItems(at:). That lets you provide an array of indexPaths, which tells the table view that you have added new entries.
You could certainly write a button action method that added one or more entries to your data model and then used the insertItems(at:) method to notify the collection view that it had new entries. If there was room in the content view of the collection view to display additional cells it would then call the data source and ask for new cells at those index paths.
Sounds like you just need to keep track of how many items you want displayed (which will increase the more that button is pressed) and use that in your UICollectionViewDataSource method. Something like:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return min(myRunningItemCount, maximumNumberOfItems) //assuming there's a maximum
}
Then you just need to call reloadData on the collection view whenever that number changes.

Select not visible cell inside a collection

Well, one might ask why should you do that ?
I have a collection view inside some view where the user can select a cell.
Then this selection is saved and later, when the user wants to enter that view again, he should be able to see his previous saved selection.
If his selection was at the end of the collection view, I will not be able to load the collection view with his previous selection, because:
for cell in collectionView.visibleCells()
// find and select previous cell
Will not loop through all cells, specifically the one the user chose (that does not exist yet).
Is there a solution to this problem?
You can remember the exact index paths of selected rows (using indexPathsForSelectedRows), but this is still not safe if your dataSource set changes/updates and the remembered indexes may become invalid with new/different set of data. Thus you should remember selection of “real world” objects (where you're filling specific cell data, like title etc.) for example by remembering object identifiers of your choice so you'll be able to re-map and re-select rows in case of reload with different data. The management of objects selection is generally completely in your hands.
Well after a lot of searching, what works for me is to set a local variable say: selectedCell , then when I want to show a previous user selected cell, i will just set the variable , and on :
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
if(indexPath.row==selectedCell)
}
I am checking if its already selected and mark it .
I could not find any other clever way of doing so automatically .

Swift grouped UITableView best practices

I'm setting up the settings page of my first Swift app and can't seem to find a clean way to set up the master-detail relationship between the settings view and a child table view of options.
My settings page is a UITableViewController with a custom layout of grouped cells. I also have a detail UITableViewController that I want to use to present options for various settings. My initial thinking led me to think that I can use a single view controller for this and just change the cells based on the segue. My largest problem is loading all the data into the cells since the grouped tables don't have prototype cells that I can call in
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) {}
Is there a commonly accepted way to set up these sort of settings table, that have a defined number of rows? I could make a viewcontroller for each setting, but that feels wasteful.
Even though it feels wasteful, it's more intuitive and less convoluted to have (segues to) different view controllers.
Your detail view controller has to
display options
return the selected option
save state
So, there are three points where you'd end up with large blocks of conditional code to determine which group of options you're dealing with, while displaying, unwinding, or preserving/restoring details.
If you added more options, a monolithic approach would only continue to grow more and more complex.
A monolithic approach is also the least flexible, if you ever needed to support a second (non-check mark) type of selection in the future.
Separating responsibilities into different (subclassed) detail view controllers means each controller can clearly and simply handle its own details. Your code will be easier to understand, maintain, and update down the road.

Manipulating data through table view cells iOS swift

firstly thank you in advance for any help and secondly I am very new to do the iOS development and swift so please bear with me and forgive me if I ask any stupid question.
MY ISSUE:
I created a table view and created an array of numbers. I iterated through the array and displayed each number in the array in a different table view cell. Now what I want to do is either have a button my table view cell or a check mark. And when ever I tap the button or the check mark the number that is being displayed on the table cell from the array is selected and then I tap another button or a check mark on a different cell and that number also gets selected and when I click the "done" button the both numbers are added and displayed on my root view.
Its kind of like a order taking app you can think of each cell as displaying the price of a food item and you can selected multiple food items and once you click done it adds up the price and displays it.
Im not looking for any advanced techniques, anything that can help me do this will be much appreciated. Again sorry for any stupid questions and thank you.
This is how you should break it down:
1) Implement the didSelectRowAtIndexPath delegate method after the table has been populated:
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
2) Within that method set the checkmark for the row:
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
3) Declare a class Array:
var numberArray: [Int]
4) Finally, implement an array extension for the addition. Call it when tapping the done button:
How can we create a generic Array Extension that sums Number types in Swift?
There's some fine tuning depending on your implementation but I hope this gives you a head start.
Key things to look at:
UITableView has a var called allowsMultipleSelection. You want to set that to true (it's false by default.)
If you want to change the way a cell looks when it is selected, then you can either look into the table view's delegate didSelectRowAtIndexPath and didDeselectRowAtIndexPath. Or if you have your own subclass of UITableViewCell, you can override the setSelected:animated: method.
The basic idea is to give the user a button to say when (s)he is done selecting cells, then look at the tableView's indexPathsForSelectedRows to find out which items were selected.

Resources