I'm trying to create a screen for entering patient information very similar to the contacts edit screen in iOS.
I think the screen should be a static table with cells for simple things like firstname, lastname, etc.
Within the static table would be cells containing embedded tables with dynamic cells. There would be an embedded table for phone numbers, another for street addresses, and another for medical providers, ... Each of these embedded tables could have zero or more entries.
Is embedding dynamic tables in a static table the right way to do this?
I don't know how to get the height of the embedded content so that I can set the height of the static cell.
This is quite an advanced topic that I cannot cover in depth now, but I will try to give you a few pointers on how to proceed.
I would advise against embedding tableviews into other tableviews.
Use a dynamic tableview.
Create a view model that provides an array of objects for the controller to render.
The controller only takes objects from the view model and decides which cells to render (no logic in the controller)
In the view model deal with all the complexities of the data (static content, dynamic sub-arrays, sections, if-else statements, ...)
Build the complex cells (address cell in your example) using for example stack views.
Dealing with multiple fields inside one cell can be tricky, you will have to do some more research on that topic.
There are many tutorials on view model architecture ("mvvm"), google it.
I hope that helps, good luck and happy hacking!
Related
In React and other web front-end frameworks, there is the concept of 'conditional rendering'. You render certain elements of the UI to the DOM based on certain conditions being true or not.
How does the concept of conditional rendering work in Xcode / Swift? Since you apparently build the UI on the storyboard, I don't know how to conditionally render elements.
A specific example: Let's say I've got an array of arrays and for each array in the array I want to render a tableview. How would I approach this problem?
Short answer: "It doesn't." That's not how iOS works.
Edit:
You can certainly write code that builds your UI from code, and if you do that, you're free to use conditional logic to decide what elements to add to your UI.
In fact, SwiftUI uses code to build a UI, and is a reactive style development platform. You should look into that.
A UITableView, as in your example, is a data-driven UI element. It uses a data source to decide what cells to display. Depending on the types of entries in the data source, it might create different types of cells. That is similar to what you describe.
It doesn't really make sense to have multiple table views on screen at once, so I'm not sure what "...for each array in the array I want to render a tableview" would look like.
I guess you could write a view controller that had a scroll view as it's content view, and when it loaded, it took your array of arrays, and used the outer-most array to decide how many instances of table views (or table view controllers, better yet) to instantiate. It would create table views/table view controllers in a loop, and install their views into the scroll view, keeping track of the geometry. Altnernately, you could put the table views in a stack view, and put the stack view into a scroll view.
However, the UX would be awkward. The user would need to drag up and down inside each table view to navigate inside it, and also drag up and down on the scroll view in order to move between table views.
Let's say I've got an array of arrays and for each array in the array I want to render a tableview. How would I approach this problem?
You would write code—presumably, Swift code, since you used the swift tag.
Let's make it even more concrete. You have a Bookcase object which has an array of Shelf, and each Shelf has an array of Book.
If you're using a storyboard, you can have a ShelfController scene in your storyboard with a single table view to display the Books in one Shelf. You can also have a BookcaseController scene with (let's say) a stack view. The stack view has no subviews because you don't know, when designing the storyboard, how many shelves you'll need to display.
Then, in Swift code, when BookcaseController is given its Bookcase model object, the BookcaseController instantiates the ShelfController scene once for each Shelf in the Bookcase. It adds each ShelfController as a child view controller, and adds each ShelfController's view (a table view) as an arranged subview of its (the BookcaseController's) stack view.
Let's say I've got an array of arrays and for each array in the array I want to render a tableview. How would I approach this problem?
You'd probably display a list of all the arrays (or whatever each array corresponds to) and a table. When the user selected one of the things in the list, you could then set the table view's data source to use the corresponding array.
That's not the only way, of course. If you really want to draw different tables for each array in the list, you can do that — you're in charge of your code. But why make things more complicated?
Since you apparently build the UI on the storyboard, I don't know how to conditionally render elements.
Storyboards aren't the only way to build a UI, and they're also a lot more flexible than just a static collection of elements. A storyboard is essentially a collection of connected scenes, where each scene is a template for a screenful of content. But your code can adjust the objects in a scene, including hiding or showing them, changing their position, and adding ore removing views. So if you want you could have a scene with a different table for each of the items in your list, and then just adjust the visibility of the various tables according to whatever thing is selected. Or you could have no tables at all, and your code could create one on the fly and insert it into the view.
In short: you're assuming too much about how storyboards work. Start reading about how view controllers work and you'll soon have a much better understanding of the kind of control you have over the UI.
I am attempting to make a custom view that looks like the attached picture. The top two cell would be static while the bottom three would scroll if there are more than the screen can fit, and only scroll within that given area. I am wondering what the best approach is to making these types of custom views. I know how to make custom UItableviewcells and have custom content in them, but I am struggling with an overall strategy to make a custom UITableview that has certain cells be static and others scroll. Should I just implement a table view to be part of the screen in storyboards? Or are there better ways to do so?
I would do this by making the top two "cells" just be UILabels, and the bottom a table view where both the cells and the table view would have a clear background. The table view should be set to have no separators between the cells, and the cells should have a UILabel with a background cooler the same as the top UILabels.
This was the result:
I normally do not like to use story board much. And prefer SubClassing UIView. It might take more time to code at first but in a long run it is easier and very dynamic to control the UI programmatically.
In your problem I would make two static UIView(s). If the two view are similar the advantage of using UIView class is that you can use same class with different data model to generate multiple views. But if you use story board you need to copy past multiple times. Hence try to create UIViews class objects as much as possible.
And then the bottom one will be a simple table view. Do not think there is much you can do in this case. Do submit some codes you have done so that we can better refine it.
I'm using Core Data to save my dynamic UITableView (not controller, AFAIK you can't have a static table view in a UITableView). I was wondering if it was possible to add a separate section to my table view with just one static cell inside? I tried looking but I couldn't find anything so far! I just need a point in the right direction.
Thanks!
As Scott says, you have to stay with a dynamic table view.
However, you can have multiple UITableViewCell's (with different reuse identifiers) in your table, so just create two different cells and return the appropriate one, based on the indexPath provided in cellForRowAtIndexPath:.
Unfortunately, a table is either completely static or completely dynamic. If part of your table view needs to be dynamic, you'll have to make the whole table view dynamic and implement the delegate methods for the static cells as well.
In my app I have a detail screen for Product objects. The UI calls for the product details to be displayed using a grouped table view type interface with 3 sections.
Some of the cells in this table are conditional. For instance, by default the third section should display a single cell that says "Register Product" and should push the registration view when tapped. If the product is already registered then the third section should instead display two cells one for Warranty and one for Servicing Information. These would each go to different screens when tapped. Also, they both need to display some kind of data on the table cell. The warranty cell says when the warranty expires and the Servicing cell says when the next servicing is due.
QUESTION (finnally): What's the best way to define the cells and sections that the table should have in any given situation. Primarily I'm looking for a maintainable way to do this since I already have some ideas about un-maintainable ways to do it.
Should I create some sort of keyed dictionary and add/remove items from it during viewWillAppear based on the Product being displayed? I'm worried the number Switch statements that I would have to use throughout the various tableView events to check what type of cell is at a given index path.
Any ideas?
Have a look at Matt Gallagher's Tableview Classes. They provide a simple and extensible framework for customizable Tableviews. Cells can be loaded from a NIB or constructed in code. There's a simple interface to provide the data for each cell (- (void)configureForData:(id)dataObject).
Populating the Tableview is easy:
[self addSectionAtIndex:0 withAnimation:UITableViewRowAnimationNone];
[self appendRowToSection:0
cellClass:[NibLoadedCell class]
cellData:#"This is row 0"
withAnimation:UITableViewRowAnimationLeft];
For persistent storage of the data I recommend to create a plist dictionary and load/save data from there. See Property List Programming Guide. For complex database structures use core data for storage.
I am writing an iPhone app. According to the design, it is supposed to contain a lot of grouped table views. In these views, the rows are frequently not similar to each other. For example, on one screen, one row is the name of a task, another is its owner, another is its description, yet another is its history (which is supposed to be an expanding box), and so on. These rows are edited in different ways. For example, the name can be entered free-form, but the owner has to be chosen from a list, which would be brought up in a further table view.
I think doing all of this programatically would drive me batty. What I want is a way to design these screens in IB. But I can't figure out how to get IB to do treat the cells individually. Is that possible?
Thanks.
In Interface Builder you create custom UITableViewCells for each row and then return the appropriate custom cell in – tableView:willDisplayCell:forRowAtIndexPath:. You also need to return the height of each custom cell in – tableView:heightForRowAtIndexPath:.
Within Interface Builder, you create a custom cell just like you would any view. You size the cell and then fill it with subviews. It's best if you create a UITableViewCells subclass for each custom cell that has IBOutlets that connect to each subview. That way you can easily access labels, imageviews, controls etc.