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开发者_如何学C 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.
精彩评论