//if it used to be 20, and I change it to 50, the cell will increase in height
cell.topDistanceConstraint.constant = 50;
UIView.animateWithDuration(0.15) {
cell.layoutIfNeeded();
}
self.tableView.beginUpdates();
self.tableView.endUpdates();
It's really easy, actually. You can set the 'estimatedRowHeight' property of your tableView =
UITableViewAutomaticDimension (make sure NOT to implement the 'estimatedHeightForRowAtIndexPath' or 'heightForRowAtIndexPath' methods).
You then use auto-layout on the UITableViewCell views. There should be constraints that essentially let the cell calculate how 'tall' it should be. For example, if you have a label in the middle of the cell that is always 20px high, you would have two constraints (top and bottom). Depending on the values of those two constraints, the table view cell can tell automatically how tall it should be.
You can then programmatically change the values of these constraints, which lets you animate the change in height, like this:
Code://if it used to be 20, and I change it to 50, the cell will increase in height cell.topDistanceConstraint.constant = 50; UIView.animateWithDuration(0.15) { cell.layoutIfNeeded(); } self.tableView.beginUpdates(); self.tableView.endUpdates();
The tableView doesn't have to have a flat array. I used a grouped type in FRC from CoreData in mine for a 2 level tableView.So my main problem wasn't dealing with the TableView constraints, but more of how do I get a tree structure into a tableView that expects a flat array since indexPath.row won't account for child comments.
Long story short, I solved problem by flattening my tree array and tracking what level the comment node is at. I then check what node level the comment is at within the "cellForRowAtIndex" and adjust the left constraint accordingly. Maybe there is an easier way, but this solved my problem without having to wedge a 3rd party framework into the app.
The tableView doesn't have to have a flat array. I used a grouped type in FRC from CoreData in mine for a 2 level tableView.
I'm not sure, but doesn't the tableView allow more levels when it's grouped?
I wouldn't mind seeing your solution, I wanted a treeview thing for browsing resources and some of the examples I've seen are overly complex.
Sure, but what do you mean grouped? Splitting parts of the tableView by Section? I've done that before, but my problem was I wanted to see Parent + Child + Child's Child all in one section. Maybe there is a way to do this?
NSFetchedResultsController *myFRC = [Contact MR_fetchController:myFetchRequest
delegate:self
useFileCache:NO
groupedBy:@"category"
inContext:localContext];
I still don't really fully understand your question. Are you trying to say there may be sub-table views inside some table view cells? If so, I would just have two types of UITableViewCell, one would be dynamically resizable and would contain a subview UITableView. The other type of cell would be the 'content' table view cell which gets shown. When being initialized, the 'cellForRowAtIndex...' would grab an object from the data array, and depending on whether it's an array or an object, I would return the table-view containing cell or the content cell. It would pass this array/data object to the UITableViewCell via a custom initializer so that it can decide how to display it.
Depending on whether a specific node has sub nodes, I would switch between one or the other, and they would have a property called 'collapsed' which indicates if they are collapsed or not. In order to do the actual collapsing, I would use auto layout like I mentioned in my previous post.
How are you getting your data and how are you managing it?So here is a screenshot of what my initial question was trying to achieve.
I wanted to know how they created the effect of having a top level comment (e.g. someone replying directly to the thread) and having all replies shift to the left (and reply to the replies.....etc...). This can potentially happen an infinite amount of times for any comment, so I can't hard code a limit on how deep the replies can go.
Example. An array contains 5 direct thread replies. The 5 top level replies also hold replies to them as well. These are all the same type (A class I named CommentModel). Each CommentModel has a property called childComments which holds the next level of comments below it etc... "childComments = nil" if there are no replies to that comment and the node stops.
0 = Top level reply directly to thread
1 = Reply to top level
2 = Reply to 1 (first reply)
3 = Reply to 2 etc....
0 -> 1 -> 1 (has to two replies directly to the top level comment node)
0 -> 1 -> 2 (has a one reply to the top level comment node and one reply to the reply node..I know it's getting confusing with redundant words)
0 -> 1 -> 2 -> 2 (one reply to top level comment node and two replies to the reply (1) node)
0 (top level comment with no replies)
0 (top level comment with no replies)
Total number of rows to view all comments: 12
So if I use the expected way cellForRowAtIndexPath, I will only get 5 rows, since the initial array has hold 5 top level comments, but each comment could have associated replies.
So, my solution (I can post code if you're curious) was using a combination of recursion and node tracking
1. Flatten array so all nested comments are moved into a flat array.
2. While I parse this, I set a property called nodeLevel which specifies how deep the reply is.
3. Pass that array to the tableView which now has the correct count to view ALL comment and replies for a particular thread.
4. I added an AutoLayout constraint out for the left margin of the cell and set it's constant = (nodeLevel * 10) which will then indent to the appropriate distance based on what level the reply is.
There may be a simpler approach or UITableView CAN deal with a tree structure, I'm just not aware of how to do it...
How are you getting your data and how are you managing it?
It sounds like you're parsing it from an RSS feed or something and loading it into an array. In that case, the RATreeView should work.
I didn't dig deep into the RATreeView to see how it was doing what it did, but I think you should be able to run their sample code and just replace it with your data feed. The rest would be cosmetics and whatnot.
If you want a leaner solution, you could just dig out the logic of RATreeView and see how they do what they do.
From the sounds of it, a CoreData FRC would be overkill with the Add/Edit/Delete part, but would have the upside of data caching.
LOL, that's exactly how I feelThe data is getting returned from REST response with JSON data. I have a PostModel type that has a "comments" property, which holds the comments for a specific post. This isn't populated until the user will select a post to view.
I looked into RATreeView but I felt it was overkill for what I wanted to do. A lot of times I feel that trying to wrap my head around 3rd Party Frameworks and getting them to work in my project, which may have slightly different use case to be more work than just doing it myself. On top of that, I typically like to know how to do things myself before using a framework that has lots of bells and whistles.
My code is actually pretty light weight. It's maybe < 25 lines of code?
Yea, I don't need the "Add/Edit/Delete" part since this is just displaying comments that were returned from the URLRequest.
Yea, if they provide documentation and specific examples on how it works then 3rd Party Frameworks are great. Most of the time though, they simply have an example program and expect you to figure out how to integrate it with with your app.LOL, that's exactly how I feel
I dig into their code and try to figure out "what do I need from this" to make it work with mine.
The things I showed in the pics above were from a 3rd party and I had to dig into it in order to make it work with iOS6 and even to make it work other 3rd party tools.
It can be a real pain. The RSS feed parser was a LOT of time to dig into and when I was done, I found that it didn't grab the pics out of the data. He left that for others to do, but nobody did it and posted it. So I have to find another tool if I want that.
I'm 100% with you on the 3rd party stuff, it can be a trap. However, there's some good code gems if you're willing to dig deep enough.
That's exactly what I had to do. Even the two slide outs didn't work with each other.Yea, if they provide documentation and specific examples on how it works then 3rd Party Frameworks are great. Most of the time though, they simply have an example program and expect you to figure out how to integrate it with with your app.
That's exactly what I had to do. Even the two slide outs didn't work with each other.
On that pic I posted, there are scrolling RSS data feeds that are shown on the right.
I downloaded several 3rd party tools to do scrolling text. Had a BAD time trying to make them work, they had so much stuff like spacing calculators, speed calculators, etc..
I couldn't even get it to scroll right unless the length of the string was greater than the length of the field, so I padded the string with spaces just to get it to work right.
This is why when programmers interview for jobs, they want to see the code, it's a PITA to try and figure out what someone else's trying to do, much less try to debug or change behavior.
That looks great. So it's a tree structure and when a cell is requested, you look at the prior cell to find the location and see if the next cell is a part of the same branch, otherwise you walk back up the array until you find out what should be the next cell.If you're curious what my solution looks like check it. It's not the prettiest yet, but works. Next is to make them collapsible.
var flattentedComments = [CommentModel]()
func parseAndFlattenComments(comments : [CommentModel]) -> [CommentModel] {
//Has top all top level Comments, so we need to iterate through each one to find their children.
for parentNode in comments {
self.flattentedComments.append(parentNode)
self.parseNode(commentNode: parentNode)
}
return self.flattentedComments
}
func parseNode(commentNode : CommentModel) {
if commentNode.childComments != nil {
for comment in commentNode.childComments! {
comment.nodeLevel = commentNode.nodeLevel! + 1
self.flattentedComments.append(comment)
if comment.childComments != nil {
self.parseNode(commentNode: comment)
}
}
}
}
Thanks, I'll dig into it a bit later.Sure, here is pretty much the logic I'm using to create the flatted tree of comments. Note this isn't perfect and each CommentModel all children as I'm not currently removing that at the moment.
Code:var flattentedComments = [CommentModel]() func parseAndFlattenComments(comments : [CommentModel]) -> [CommentModel] { //Has top all top level Comments, so we need to iterate through each one to find their children. for parentNode in comments { self.flattentedComments.append(parentNode) self.parseNode(commentNode: parentNode) } return self.flattentedComments } func parseNode(commentNode : CommentModel) { if commentNode.childComments != nil { for comment in commentNode.childComments! { comment.nodeLevel = commentNode.nodeLevel! + 1 self.flattentedComments.append(comment) if comment.childComments != nil { self.parseNode(commentNode: comment) } } } }
Let me know if you have any questions on how it works. Long story short, I'm removing the treed comments and pushing them into a single leveled array. But I have a property called nodeLevel that keeps track at what position they should be at so they can be indented properly according to their response level.
Thanks, I'll dig into it a bit later.
BTW, what parser are you using to grab your feeds?
I used item 2.4 from this site:
http://codewithchris.com/make-a-iphone-app-for-your-wordpress-site/
It wasn't complete in that it doesn't grab pics. I haven't found a replacement, maybe yours is better. That tutorial in that link was pretty good otherwise.
I'm pretty sure the code is on GitHub, but if you read it, it had a "to do" part in the description where he talks about parsing out the rest of the stuff.
I think Apple had a great one in some sample that included caching for off-line reading, but I haven't dug into that code yet. So much to learn...
[edit]
https://github.com/mwaterfall/MWFeedParser
Here's a direct link, it has > 2K stars and dates back to 2010, but still has some missing functionality. I wonder if everyone went in another direction.