Reputation: 10762
I have a UITableView
and a UITableViewController
that I use in multiple screens in my application.
I recently spoke to the product team at my organization, and they have requested that for one of these screens, I prepend about 15 cells which look and function very differently.
After googling around, it seems that the only way to do this is to complicate every implemented UITableViewDelegate
method with something like:
if section == 0 {
...
}
if section == 1 {
...
}
Which I don't want to do, because the other screens that show this table, do not need this logic, and suddenly reusability becomes way more complex.
Ideally, what I would like is to vertically stack two table views, such that one is attached to the bottom of the other.
Is something wrong with my architecture, or is there simply no nice way of doing this in IOS?
Upvotes: 1
Views: 46
Reputation: 10762
@Fennelouski, thank you so much for you tips, I actually ended up going with your unrecommended option #4:
Put both table views in a container view
The primary reason I went in this direction is because in the past, when attempting to put scrollviews inside of other scrollviews, I found unexpected behavior regarding bouncing. Even if I set bounces
to false
on the nested scrollviews, I found that the parent scrollview would not move when the dragging started with the nested scrollview not quite at the end of it's content.
My solution ended up not being terrible (partly because my application is built with a framework that I designed, which allows for nifty eventing). I'll outline it here:
first
and second
to a UIView, container
controlled by a UIViewController, controller
.container
.first.contentInset.bottom
to second.contentSize.height
and set second.contentInset.top
equal to first.contentSize.height
(this must be done to allow for flicking one table hard enough, to hit the end of the other table.. and must be done again anytime either of the tables change height)second.backgroundColor
to be clear
second
's hittest method pointInside:withEvent:
to return point.y > 0
(this is done, so the touch events on the empty space above second
will translate down to first
)scrollViewWillBeginDragging:
is called, store which table began dragging (I used a property called last_dragged
).scrollViewDidScroll:
is called, position the table that was not last_dragged
based on the offset of the table that was last_dragged
This is the code that I used for controller
(which, yes, is written in ruby, but hopefully you'll be able to read it as sudo-code)
def load_view
content.add_subview first, size: content.size
content.add_subview second, size: content.size
set_content_offsets
listen_for_events
set_second_y
end
def set_content_offsets
first.content_inset_bottom = second.content_size_height
second.content_inset_top = first.content_size_height
end
def listen_for_events
listen_to_first
listen_to_second
end
def listen_to_first
first.on('refresh', method(:set_content_offsets))
first.on('begin_drag', method(:second_dragged))
first.on('scroll', method(:scroll))
end
def listen_to_second
second.on('refresh', method(:set_content_offsets))
second.on('begin_drag', method(:second_dragged))
second.on('scroll', method(:scroll))
end
def first_dragged
@last_dragged = :first
end
def second_dragged
@last_dragged = :second
end
def scroll
if @last_dragged == :first
set_second_y
else
set_first_y
end
end
def set_first_y
first.content_offset_y =
first.content_size_height +
second.content_offset_y
end
def set_second_y
second.content_offset_y =
first.content_offset_y -
first.content_size_height
end
Upvotes: 0
Reputation: 2431
I've had to do something similar a couple of different times and here's what I was left with:
Add special cases based on section. Surprisingly, I found this to be the easiest to read and maintain. Just use static and clear variable names instead of if (section == 0)
.
Create a special cell for row 0 that contains a table view. This isn't the easiest thing to do, but it can work nicely for being able to break your code up into multiple files which generally works better for maintenance. This does become a pain when you're sorting delegate methods, but once that is worked out then it is a very dynamic solution.
If you're not using headers, then do the same as #2 but use a header for your special case. This works well (if available) when the spec changes because you can just put the view in a different header or footer.
Put both table views in a container view of some sort. I tried this, it wasn't pretty. I don't recommend.
Add both tables into another table. This can be done to divvy up where the cells come from. Doing this, you can subclass UITableView
and create a flag to add the special table to the table. This isn't so much a solution as both a recommendation and a starting point.
Whichever option you decide, make sure it's legible. UITableView
can get complicated when you're not heads down in it.
Upvotes: 3