I have a weird design case in which to implement I need to place two UITableViews on the same view. I would just use sections, but I need an index on the second table.
I'd like them to both scroll together like they were actually two sections of the same table view. Is this possible?
Here's a basic mockup illustrating why:
As far as I understand it, you cannot move the index. Also, when you add an index to a table, it appears over the entire tableview, not just one section.
If I have to implement this as two table views, they both need to scroll as if they were one. If it's possible to do this using sections, that's even better.
Update
After seeing your update my old answer is not very good but I'll leave my previous answer for anyone else who wants it.
New answer - It depends how you want the tables sync'd.
If you know
Which cells are in the top 5
How tall each cell is
The offset the table view
Then you can calculate which cell is visible at the top of the top 5 table. You can use this information to scroll the bottom table to the correct index.
Old answer
I'm with the other guys not sure why you would want to or if I am misinterpreting but it's pretty simple.
UITableView is a subclass of UIScrollView so you can set yourself as the UITableViewDelegate and override
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
{
UITableView *slaveTable = nil;
if (self.table1 == scrollView) {
slaveTable = self.table2;
} else if (self.table2 == scrollView) {
slaveTable = self.table1;
}
[slaveTable setContentOffset:scrollView.contentOffset];
}
This gives me something that looks like this:
The top UITableView is self.table1 and the bottom is self.table2 if either table is scrolled the scrolling is mirrored in the other table.
in swift this code:
func scrollViewDidScroll(scrollView: UIScrollView) {
if tb_time1 == scrollView {
tb_time2.contentOffset = tb_time1.contentOffset
}else if tb_time2 == scrollView {
tb_time1.contentOffset = tb_time2.contentOffset
}
}
From the mock-up it seems like this can be accomplished with a single UITableView with two sections.
Instead of maintaining two tableViews you could maintain two collections (one for each section). Then in cellForRowAtIndexPath choose the collection to use based on the section specified in the indexPath.
Related
When a user adds an item to my list, I want to scroll to the new row, highlight it, and select it (which will push a new controller). The key part is waiting for the scroll animation to complete before pushing the new controller.
In this answer, I learned how to use the animation delegate to wait until the scroll is complete.
However, if the insertion row is already on scree, the table view will not scroll and the method will not fire.
How can I wait to push the new controller until the end of the scroll, and deal with the case where no scroll will be initiated - and how might I tell the difference between each case?
The easiest way to check whether a given row is visible in your table view is something like this:
if (!CGRectContainsRect([self.tableView bounds], [self.tableView rectForRowAtIndexPath:indexPath])
{
// the row is partially outside the table view’s boundaries and needs to be scrolled for full visibility
}
else
{
// the row is within the boundaries and does not need to be scrolled
}
Try creating a method to see if scrolling is needed. If no scrolling is needed, call the push right away, otherwise wait for the delegate call and push.
- (BOOL)isSrollingingNeededForIndexPath:(NSIndexPath *)indexPath {
NSArray *visibleIndices = [self.tableView indexPathsForVisibleRows];
for (NSIndexPath *visibleIndexPath in visibleIndices)
if ([indexPath compare:visibleIndexPath] == NSOrderedSame)
return NO;
return YES;
}
Edit: Good point. Since indexPathsForVisibleRows is used for data rendering.
You could do essentially the same thing with indexPathsForRowsInRect where you use the content.offset.y and the tableview.frame.size.height to determine your "visible rect".
Then to account for partially visible rows at the top and bottom you could add rowHeight-1 to the top of the rect and subtract rowHeight - 1 from the bottom of the rect. Code shouldn't be too gnarly if you have static height rows. If you have varying height rows it would still work, but it would be a bit more involved.
All said though, it seems like a lot of code for something which you'd think would have a simple answer.
I would like to know if there is any sneaky way of getting a UITableViewCell to appear at the beginning of a UITableView no matter what the array that is going to populate the tableview contains?
I am having issues where I would like to have a "select all" cell at the top of the tableview but currently having issues trying to adjust the arrays I have going into the tableView:cellForRowAtIndexPath:
Not sure of your end goal, but there are many ways some easier (sneaky ways) than others depending on your needs. It sounds like your items are fairly static, so you can just insert them before you display or update the table row.
say you have a datasource called self.items and you did something to get data. Maybe in your app you are round tripping to some data source based upon input, like sort selectors or from the search bar delegate.
try something like this in the area where you load your datasource.
NSString *myCustomObject = #"Jump To Songs";
self.items = [self getGetMovieList];
[self.items insertObject:myCustomObject atIndex:0];
[self.tableView reloadData];
Another easy way would be to add sections to your table and just make the first section your navigation items.
Note: you may need to handle the actions in didSelectRowAtIndexPath......
there you go, not so sneaky, but pretty simple.
be well
You can make two types of UITableViewCell, then return the "select all" one if indexPath.row == 0.
On the other hand, how about just make a UIView for the "select all" functionality, and set it as the tableHeaderView of your table view?
Could you please help me with circular scrolling in tableview please.
I want that if I scroll down tableview, the rows should go in the reverse way --
it should appear that move back around (bottom rows go around and now come back down from the top) i.e, cyclic scrolling basically.
How can I do so. Any suggestions please.
Thanx in advance.
You could "fake" the cyclic scrolling repeating the same cells all over again. In the numberOfRowsInSection method, return n times the actual number of rows. Make sure n is big enough.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return numberOfActualRows*100;
}
Then in the cellForRowAtIndexPath method (and elsewhere) use the mod operator (%) to return the proper cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger actualRow = indexPath.row % numberOfActualRows;
...
}
You may want to hide the sroll indicator.
self.tableView.showsVerticalScrollIndicator = NO;
You may also want to scoll the table view to the middle before you display the table so scrolling backwards works fine.
[self.tableView scrollToRowAtIndexPath: [NSIndexPath indexPathForRow:[self tableView:self.tableView numberOfRowsInSection:0]/2 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
Of course, the user would eventually hit the bottom or the top if he/she kept scrolling over and over.
This question has already been asked: implementing a cyclic UITableView
I'm copying that answer here to make it easier because the asker hasn't ticked my answer.
UITableView is same as UIScrollView in scrollViewDidScroll method.
So, its easy to emulate infinite scrolling.
double the array so that head and tail are joined together to emulate circular table
use my following code to make user switch between 1st part of doubled table and 2nd part of doubled table when they tend to reach the start or the end of the table.
:
/* To emulate infinite scrolling...
The table data was doubled to join the head and tail: (suppose table had 1,2,3,4)
1 2 3 4|1 2 3 4 (actual data doubled)
---------------
1 2 3 4 5 6 7 8 (visualising joined table in eight parts)
When the user scrolls backwards to 1/8th of the joined table, user is actually at the 1/4th of actual data, so we scroll instantly (we take user) to the 5/8th of the joined table where the cells are exactly the same.
Similarly, when user scrolls to 6/8th of the table, we will scroll back to 2/8th where the cells are same. (I'm using 6/8th when 7/8th sound more logical because 6/8th is good for small tables.)
In simple words, when user reaches 1/4th of the first half of table, we scroll to 1/4th of the second half, when he reaches 2/4th of the second half of table, we scroll to the 2/4 of first half. This is done simply by subtracting OR adding half the length of the new/joined table.
Written and posted by Anup Kattel. Feel free to use this code. Please keep these comments if you don't mind.
*/
-(void)scrollViewDidScroll:(UIScrollView *)scrollView_
{
CGFloat currentOffsetX = scrollView_.contentOffset.x;
CGFloat currentOffSetY = scrollView_.contentOffset.y;
CGFloat contentHeight = scrollView_.contentSize.height;
if (currentOffSetY < (contentHeight / 8.0)) {
scrollView_.contentOffset = CGPointMake(currentOffsetX,(currentOffSetY + (contentHeight/2)));
}
if (currentOffSetY > ((contentHeight * 6)/ 8.0)) {
scrollView_.contentOffset = CGPointMake(currentOffsetX,(currentOffSetY - (contentHeight/2)));
}
}
P.S. - I've used this code on one of my apps called NT Time Table (Lite). If you want the preview, you can check out the app: https://itunes.apple.com/au/app/nt-time-table-lite/id528213278?mt=8
If your table can sometimes be too short, at the beginning of the above method you can add a if logic to exit when data count is say for example less than 9.
I haven't done this myself, but you could try the approach you'd use with a UIScrollView to implement cycling scrolling of views (after all UITableView is a subclass of UIScrollView).
I would do as follows:
Create a UITableView with an arbitrary number of cells (at least 7 but will need more to prevent fast scrolling bumping at the end)
Position your UITableView so the centre cell is visible
Maintain a pointer to the index of the cell you are looking to display
In your cellForRowAtIndexPath: use your pointer to as an offset and add the row to it to get the cell that you want
When the UITableView has stopped moving (your UITableViewDelegate can serve as UIScrollViewDelegate so you can use scrollViewDidEndDecelerating). Set your offset index to the current cell, move the table view back to the centre cell without animation and reload the data.
The issue you will have is if the user keeps scrolling without stopping they will eventually hit the bumpers as the number of cells in the table is reached.
Hope this helps, and please post back if you get this working and it looks at all reasonable.
Regards
Dave
This is very much difficult to implement. However, take a look at the ScorllingMadness, which shows the demo of nested (cyclic) pages in a scroll-view.
You need to use the similar kind of trick here as UITableView is a subclass of UIScrollView.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Can you animate a height change on a UITableViewCell when selected?
I've been doing a lot of Googling to try to figure out the correct way of doing this, and so far I am at a loss.
I have subclassed UITableViewCell with my own view and I am trying to animate the height of a UITableViewCell to expand when it is selected, and to contract when it is selected again. This table has the potential to contain thousands of rows, so I don't want to override the tableView's heightForRowAtIndexPath. Ideally I'd like to be able to have more than one cell expanded at a time, but that isn't as critical. What is the best way to do this?
Thank you,
Justin
There is no other mechanism for specifying cell height than heightForRowAtIndexPath. Unless you're properly accounting for the expanded cell in that method you're going to find your other cells either running over it or hidden under it. From boneheaded code where I forgot to set up heightForRowAtIndexPath, I'm pretty sure your other cells will be displayed over it.
Since you're talking thousands of rows, we'll assume the user can't rearrange the cells.
What you could do is store the expanded cell's index path when the user taps a given cell. Then, heightForRowAtIndexPath might look like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
if ([indexPath isEqual:lastSelectedIndexPath])
{
return 80;
}
else {
return 44;
}
}
If you really want multiple selections, you could store the appropriate index paths to an array and check for them like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
CGFloat cellHeight = 44;
for (NSIndexPath *expandedIndexPath in expandedIndexPathsArray)
{
if ([indexPath compare:expandedIndexPath] == NSOrderedSame)
{
cellHeight = 80;
break;
}
}
return cellHeight;
}
Getting the animation to look right will take some work. I've toyed with this particular UI idea for awhile now and could never bring myself to sit down and really make it happen. One thing you could do is display a dummy view that animates while you're updating the tableview behind it.
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPathswithRowAnimation:(UITableViewRowAnimation)animation
could be of interest for this as you might be able to use the cell animations to simulate movement of the cells below to accommodate your expansion.
If you can forgo animating the cell's frame altogether, you could do an opacity animation of the expanded data once the new height has been set.
It's a toughie but if you make it work I bet it'll be pretty cool. Good luck.
I'd like to add section headers to my grouped table view's sections but I'd like them to appear seamless (see image). The default, as we're all well aware of, is rounded top corners on the first row of a grouped table view cell so it ends up looking like crap when you merge them.
Any way to specify when indexPath.row = 0 that the UITableViewCell should use row style "middle" or something like that?
If not then what are my options? I guess I could scratch the section header and use Row 0 as a quasi-header then push my array data +1 to fill the rest of the table? I'd rather not roll my own from scratch...if possible.
Sample Table http://img35.imageshack.us/img35/8181/sampletable.png
Edit:
"Crap" looks like this:
alt text http://img25.imageshack.us/img25/9748/crapsection.png
Don't do what you're doing, it's against HIG
Ok, ok, I'll tell you how to do it:
You're going to want to do your own cell background views. The default grouped one is not what you want.
When a tableview asks you for a cell, set its backgroundView and selectedBackgroundView to something that looks appropriate for its place in the tableview.
Usually, this means a UIImageView with the appropriate image, though you can go wild here with a custom view, but there are gotchas.
So in your case, you would do
if (indexPath.row > sectionRowCount - 1) {
//Not the last row
//Put in the middle background
} else {
//Put in the end background
}
Then you'll want a custom table section header, but that's pretty easy.
In your case, you probably won't have to worry about when there's just one row, so that makes things even easier.
Take a look at the tutorial here:
cocoa with love basically what you need is 3 different images. One for the top row, one for the bottom, and a 3rd for the middle rows.
You could also not use the section header, but instead use a custom cell as the first cell of the section. So when ([indexPath row] == 0), return a custom cell that is the "header" and then return the "regular" cells (offset by one row) for the rest. You'll also have to make adjustments to the numberOfRowsInSection function to return +1.