Calculating actual size of UITableView - iphone

I need to scroll my UITableWay programmatically. Scrolling is performed when user touches a button. I want my UITableWay scroll up until the bottom of the actual table reaches the bottom of the table's frame. I thought it would be easy to implement by doing something like this:
static CGFloat offset;
- (IBAction)pageUpClick:(id)sender
{
if (offset < ([rankingTableView numberOfRowsInSection:[rankingTableView numberOfSections] - 1] * rankingTableView.rowHeight) - rankingTableView.frame.size.height)
{
offset += 10.0;
[rankingTableView setContentOffset:CGPointMake(0, offset)];
}
}
but it doesn't work. The table just goes up even when the rows are over the bottom of the frame. i cannot find the actual size of my table.... but obviously it is quantity of rows * row height. since i want my scrolling stop when both the bottom of the table and the bottom of its frame lies on the same line i'm substracting the height of the frame. And all in vain. My only possible explanation is maybe i'm using wrong section number (i'm assuming it to be [rankingTableView numberOfSections] - 1 cause i got just one section ) ... but how can i check it? Any ideas? Thanks in advance

What about contentSize property? Try this:
CGSize mySize = [myTableView contentSize];

Related

UITableView scrolling although numberOfRows is 0

I am having a very difficult time understanding this. I have a UITableView which frameHeight is set at 200. Although I've set numberOfRows to 0, this UITableView still scrolls, any idea why? My understanding is that it will only scroll if the contentView height is bigger than the frameHeight right? But in the case of the numberOfRows of 0, the contentView should be 0?
First Solution use UITableViewStyleGrouped style
Because by default it is set to UITableViewStylePlain which shows empty cells too after displaying filled cells.
Second Indirect Way
if (table.contentSize.height < table.frame.size.height) {
table.scrollEnabled = NO;
}
else {
table.scrollEnabled = YES;
}
You can run this code after calling reloadData on the table, and it calculates the right sizes and appears to work.
Edit 1
Another way is to disable Bounce -> Bounces/ Bounce Vertically
Hope this will solve your problem

UIImageView stops resizing when fast scrolling a UIScrollView

So i got an imageView inside a ScrollView that should resize, which works the way i want (see a small video here: https://dl.dropbox.com/u/80699/scroll.m4v)
what i did is setting up a UIScrollViewDelegate and using the scrollViewDidScroll method to resize my image based on the scrolling offset
- (void)scrollViewDidScroll:(UIScrollView *)aScrollView
{
CGFloat scrollViewOffset = aScrollView.contentOffset.y;
if(scrollViewOffset < 0.0f) {
// postition top
CGRect imageViewRect = self.imageView.frame;
imageViewRect.origin.y = scrollViewOffset;
if(scrollViewOffset < 0.0f && scrollViewOffset >= -50.0f) {
CGFloat newBackdropHeight = kImageHeight - scrollViewOffset;
imageViewRect.size.height = newBackdropHeight;
}
self.imageView.frame = imageViewRect;
}
}
whats basically happening here is, that if the user is scrolling upwards when he is on the top (bounces enabled) the imageView expands with the scroll until a certain amount of offset(here 60px).
the problem with this is, that if i scroll very fast, the image stops resizing, but the rest of the scrollview scrolls fast down like it would normally do. then, when the scrollview snaps back, the image expands immediately and then scales down like it should (see video here: https://dl.dropbox.com/u/80699/scroll2.m4v).
with this behavior, the user-expierience is not very nice and the user sees a jumping image.
does anybody know how i could fix this?
here is a small sample project if you want to see the behavior yourself: https://dl.dropbox.com/u/80699/scroll.zip
thanks for your help!
if anything is unclear, PLEASE leave a comment
I had a quick look at your test project, and I believe the issue is that when you scroll quickly, by the time the callback is called the Y offset is greater than -50, so the image view is not resized.
I solved this by removing the inner if condition and giving the backdrop a maximum height:
if(scrollViewOffset < 0.0f) {
// postition top
CGRect imageViewRect = self.imageView.frame;
imageViewRect.origin.y = scrollViewOffset;
CGFloat newBackdropHeight = kImageHeight - MAX(scrollViewOffset,-50.0);
imageViewRect.size.height = newBackdropHeight;
self.imageView.frame = imageViewRect;
}
Hope that helps

How to zoom when scroll UIScrollView

I add few labels in UIScrollView and I want when I scroll, the the middle label font size can become bigger. And the previous middle label font size shrinks to smaller. And the change happens gradually. Like below. Label 1 move to left shrink smaller and label 2 move to middle becomes bigger. All labels in a UIScroll view.
I tried some, like when scroll I tried zoom scroll page, seems complex than I thought...
Anyone has good idea? Thanks!
Pretty simple really. Just stick a UIScrollViewDelegate to the scrollview and do something like this..
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
for (int i = 0; i < [scrollView.subviews count]; i++) {
UIView *v = [scrollView.subviews objectAtIndex:i];
float position = v.center.x - scrollView.contentOffset.x;
float offset = 2.0 - (abs(scrollView.center.x - position) * 1.0) / scrollView.center.x;
v.transform = CGAffineTransformIdentity;
v.transform = CGAffineTransformScale(v.transform, offset, offset);
}
}
But, if you aren't impressed by the affine transform, you could still scale the rect using the offset factor and set the UILabel to adjustsFontSizeToFitWidth... and you are done!
Just make sure there is enough space! Else it could get out of hand very easily.
Assumptions :
There are no other views in the scrollview apart from these labels.
Its required to work just horizontally.
It could be done with CoreAnimation. You have to keep the index of the main label (that one in the center), and after scrolling is done or when scrolling starts (use some proper for you method in UIScrollViewDelegate) and simply shrink side labels by animation.
Just make the size of the font bigger (with an animation block) when it is the middle one, and smaller when it is not.
You can add a category to UILabel with -(BOOL)isMiddle and set it to true/false.

How can I stop UITable from overriding the content offset I set when it is decelerating?

I have a table that I'm doing some special loading for. The user starts scrolled to the bottom. When the user scrolls near the top, I detect this through scroll view delegate methods, and I quickly load some additional content, and populate more of the top part of the list. I want this to look seamless, like an "infinite scroll" upward. To do this, I have to set the content offset, so that the user doesn't see the table "jump" upward. When I scroll slowly, this works perfectly. When I scroll quickly, so that the table is decelerating, the content offset I set is ignored. Here is the code I'm using:
CGFloat oldHeight = self.tableView.contentSize.height;
CGFloat oldOffset = self.tableView.contentOffset.y;
self.tableContentsArray = newTableContentsArray;
[self.tableView reloadData];
CGFloat newHeight = self.tableView.contentSize.height;
CGFloat newOffset = oldOffset + (newHeight - oldHeight);
self.tableView.contentOffset = CGPointMake(0, newOffset);
So if I scroll up quickly with a table 100px high and hit the top while decelerating, I load more data, get a new table height of, say, 250px. I set the offset to 150. However, since it's still decelerating, the Apple code leaves the offset set to 150 for .1 seconds or something, then goes to the next calculated offset for deceleration, and sets the offset to 0, which makes it look to the user like they just skipped 150px of content, and are now at the new top of the list.
Now I'd LOVE to keep the acceleration from the list, so that it keeps going up for a while, slows down, and ends up somewhere around 120px offset, just like you would expect. Question is, how?
If I use [self.tableView setContentOffset: CGPointMake(0, newOffset) animated: NO]; it stops the content offset from being ignored, but stops the list dead.
We had an interesting situation like this at work a few months back. We wanted to use the UITableViewController because of it's caching, loading, and animations, but we wanted it to scroll horizontally (in your case it would be scroll upward). The solution? Rotate the table, then rotate the cells the other direction.
In your case, the code would look like this:
#define degreesToRadian(x) (M_PI * (x) / 180.0) in the header
- (void) viewDidLoad {
[super viewDidLoad];
self.table.transform = CGAffineTransformMakeRotation(degreesToRadian(-180));
...
}
Then rotate the cell, so it appears in the right orientation for the user
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
cell.transform = CGAffineTransformMakeRotation(degreesToRadian(180));
}
Now you can postpend your cells like any normal table, and they'll be added on top instead of the bottom.
I am afraid you are trying to do things too complicated without really understanding them.
Do you really have an infitite table or a very long table? I think it would be possible to just tell the table it has 1000000 cells. Each cell is loaded when you need it. And that's basically what you want to do.

Scrolling speed during UITableView re-ordering mode (not performance related)

Is there a way to increase the speed that you can drag a cell up/down during a table's movable row mode of a UITableView? For instance, there seems to be a standard speed that the table will allow you to drag the cell when you are moving it around and the scroll speed seems to increase if you hold it near the top/bottom edge of the device screen. For a given cell height and a whole bunch of cells, this might take a while to re-order them all if I have to use their standard slow scrolling.
So basically, I would like to increase the speed that it scrolls up/down when you are dragging the cell so it won't take as long to get to where you want to drop the cell in place.
I understand that you can speed up the moving process by decreasing cell height to place more cells on the device screen, but I'd rather do this only if I can't increasing scrolling speed.
Any suggestions or ideas from past experiences with this? Any advice is greatly appreciated!
Here you go. A proof of concept of a speed enhancer of the scroll when you move a cell, SDK 3.1. It may not pass Apple's requirements since overriding _beginReorderingForCell and _endReorderingForCell looks a little off-spec. There are other ways to determine if a cell starts or ends reordering (e.g. subclassing UITableViewCell and finding some measure) but this is the easiest I think.
The approach is quite simple: for every movement of Y pixels down, we move 2*Y pixels down, only when reordering.
The problem is that the currently dragged cell is a subview of the table view, so it shifts with the table view if we move it. If we are to correct for that within this setContentOffset, it has no effect since the position of the cell will be set based on values calculated apart from the current contentOffset. Therefore we correct an instant later using performSelector.
I left the debugging lines in there for convenience. All you need to do is to use FastUITableView instead of UITableView (esp. in you NIB)
You may of course want to add some timing things, so that the speed only goes up after 1 second or so. That will be trivial.
#interface FastUITableView : UITableView
{
UITableViewCell *draggingCell;
CGFloat lastY;
}
#end
#implementation FastUITableView
-(void)_beginReorderingForCell:(UITableViewCell*)cell
{
printf("begin reordering for cell %x\n",cell);
draggingCell = cell;
lastY = -1.0f;
[super _beginReorderingForCell:cell];
}
-(void)_endReorderingForCell:(UITableViewCell*)cell wasCancelled:(BOOL)cancelled animated:(BOOL)animated
{
printf("end reordering for cell %x\n",cell);
draggingCell = nil;
[super _endReorderingForCell:cell wasCancelled:cancelled animated:animated];
}
-(void)setContentOffset:(CGPoint)pt
{
if ( !draggingCell )
{
[super setContentOffset:pt];
return;
}
if ( lastY < 0 ) lastY = pt.y;
CGPoint fast = pt;
float diff = pt.y - lastY;
//diff *= 0.5; /// <<--- control speed here
fast.y = pt.y + diff;
if ( fast.y > self.contentSize.height - self.superview.frame.size.height )
{
CGFloat corr = fast.y - self.contentSize.height + self.superview.frame.size.height;
printf("Correction: %f\n",corr);
fast.y -= corr;
diff -= corr;
} else if ( fast.y < 0.0f ) {
CGFloat corr = -fast.y;
printf("Correction: %f\n",corr);
diff += corr;
fast.y += corr;
}
[self performSelector:#selector(moveCell:) withObject:[NSNumber numberWithFloat:diff] afterDelay:0.01];
lastY = fast.y;
// printf("setting content offset: %f -> %f of max %f\n",pt.y, fast.y, self.contentSize.height);
[super setContentOffset:fast];
}
-(void)moveCell:(NSNumber*)diff
{
CGRect frame = draggingCell.frame;
frame.origin.y += [diff floatValue];
// printf("shifting cell %x with %f\n",draggingCell,[diff floatValue]);
draggingCell.frame = frame;
}
If the list is going to get that long, you may want to consider other reordering mechanisms. For example, my Netflix queue includes a number in each call specifying the order of the queue, 1 for the movie about to ship, 2 for the next and so on to 187 or so for the most recent additions to the queue. I can drag an entry to reorder like on the iPhone, but I can also change the order numbers in the cells to reorder the entries, which is much easer than having to drag #187 to the 10th spot in the queue. There is also a button in each entry to put that entry on the very top.
In your app, you can add extra controls in edit view to assist in reordering such as the order number or "up/down 10" buttons.
If there are common reasons your users would want to order entries, you can have a button that handles that, such as "move up to next nearest blue entry."
From my experience, tableView scroll speed depends on distance between dragged cell and content origin/end points.
So to increase scroll speed, you don't need to subclass UITableView. Instead, you can set contentInset property of a tableView.
For example, call this in viewDidLoad:
tableView.contentInset = UIEdgeInsetsMake(64, 0, 64, 0)
Value 64 assumes that there are statusBar and navBar above tableView, top/bottom constraint between tableView and superView is set to 0 and edgesForExtendedLayout is set to .all.
That tableView goes under navBar and statusBar but because of contentInset it looks like it's attached to navBar.