Animated Sorting in UITableView

No Comments

Let me share another rather simple but neat trick which is quite useful when you need to sort a list of items visually represented by UITableView. Let’s say we have an NSArray holding a list of cities stored in arbitrary order. And in your app you’d like to offer an option to sort the list in one or the other way.

Sorting as such is very easy to implement since NSArray class already offers a number of methods (sortedArrayUsing…) which allow you to get the sorted version of the array by passing one of the following: NSSortDescriptor, comparator block, sorting C function or selector of the sorting method. To update the table view, you would then probably call [self.tableView reloadData].

That works just fine but wouldn’t it be better to provide nice animated feedback to user by moving table view cells into right slots? This is almost just as easy. The key to the solution is to use batch update mechanism built right into UITableView allowing to apply multiple changes all at once. The animation of the table view cells would be then achieved by already available [UITableView moveRotAtIndexPath:toIndexPath:]. We just need to calculate source and destination index paths for each cell which needs to be moved since the underlying data element changed it’s position during sorting operation.

Let’s have a look at the code:

- (IBAction)sort {
    // We need an unsorted copy of the array for the animation
    NSArray *unsortedList = [self.cities copy];
    // Sort the elements and replace the array used by the data source with the sorted ones
    self.cities = [self.cities sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        return [obj1 compare:obj2];
    // Prepare table for the animations batch
    [self.tableView beginUpdates];
    // Move the cells around
    NSInteger sourceRow = 0;
    for (NSString *city in unsortedList) {
        NSInteger destRow = [self.cities indexOfObject:city];
        if (destRow != sourceRow) {
            // Move the rows within the table view
            NSIndexPath *sourceIndexPath = [NSIndexPath indexPathForItem:sourceRow inSection:0];
            NSIndexPath *destIndexPath = [NSIndexPath indexPathForItem:destRow inSection:0];
            [self.tableView moveRowAtIndexPath:sourceIndexPath toIndexPath:destIndexPath];
    // Commit animations
    [self.tableView endUpdates];

I hope you enjoyed this example. You can download the full sample project here: AnimatedTableSorting. Take care!

{facebook-share} Bookmark and Share

Animated resizing of UITableView header

No Comments

Other day i was working on a project in which we had a UITableViewController configured with a UITableView in which tableHeaderView property would be set to a custom UIView reference. The custom view is then used to display variable amount of information and it was required that it shrinks when the content in it becomes less. So, i tried a few things and it turned out that UITableView considers the header view for the layout calculations only once you set it. When you change a frame of the header view, the UITableView is not getting aware of this.

The solution to the described problem was then rather simple: just put the tableHeaderView property assignment operation inside of the animation block in which you would change the frame of the header view itself. Then Core Animation thread will set the property, every time, frame is adjusted. Something like that:

// Calculate new frame size for the table header
CGRect newRect = ...;
// Get the reference to the header view
UIView *tblHeaderView = self.tableView.tableHeaderView;
// Animate the height change
[UIView animateWithDuration:0.5 animations:^{
    tblHeaderView.frame = newRect;
    self.tableView.tableHeaderView = tblHeaderView;

Typical scenario would be to put an Ad banner into the UITableView’s header and then animate it away when it becomes unavailable or so. The initial problem i had did cost some research, so i thought it would be worth sharing. Hope you’ll find it useful.

{facebook-share} Bookmark and Share

Customized UISlider with visual value tracking



This is my first blog post on programming ever. So, please don’t be too picky;-) For a project i am currently working on i had to create a custom control which looks like a normal UISlider but provides a feedback to the user on which value he or she just set by moving it. Below you see how the final implementation is actually looking (Fig. 1). As a lazy programmer i first looked around and stumbled upon similarly looking ELCSlider described in the following blog-post. But i immediately had two complaints: it seemed to heavyweight and it was utilizing (or even abusing) the mighty UIPopoverViewController to create a small popup view showing the current slider value. So, i decided to go and implement the control myself with as less coding involved as possible.

Custom slider with popup showing current value

Fig. 1

Tracking touch events

To determine when the Value-Popup subview has to be shown (or dismissed) and when it has to be updated, i have overriden following UIControl methods in the UISlider subclass implementation:

#pragma mark - UIControl touch event tracking
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    // Fade in and update the popup view
    CGPoint touchPoint = [touch locationInView:self];
    // Check if the knob is touched. Only in this case show the popup-view
    if(CGRectContainsPoint(self.thumbRect, touchPoint)) {
        [self _positionAndUpdatePopupView];
        [self _fadePopupViewInAndOut:YES];
    return [super beginTrackingWithTouch:touch withEvent:event];
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    // Update the popup view as slider knob is being moved
    [self _positionAndUpdatePopupView];
    return [super continueTrackingWithTouch:touch withEvent:event];
- (void)cancelTrackingWithEvent:(UIEvent *)event {
    [super cancelTrackingWithEvent:event];
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    // Fade out the popoup view
    [self _fadePopupViewInAndOut:NO];
    [super endTrackingWithTouch:touch withEvent:event];

In  beginTrackingWithTouch: it is checked if the touch entered slider’s knob boundary. Only if it is the case the popup should be shown, since there is no endTrackingWithTouch: call following otherwise (e.g. if you touch the slider’s tracks).

Deriving a Popup-View position

The custom UISlider subclass includes a method which calculates a frame rectangle of the slider knob. This rectangle is then used as basis for calculating the popup-view frame by adding some offsets here and there:

- (CGRect)thumbRect {
    CGRect trackRect = [self trackRectForBounds:self.bounds];
    CGRect thumbR = [self thumbRectForBounds:self.bounds
    return thumbR;

Implementing a Value-Popup UIView subclass

I would not go deep into the details of this particular subclass. You can download the corresponding Xcode project for further study. Let’s just have a quick look at the drawRect: method of this UIView subclass. It creates two paths using UIBezierPath (available starting with iOS 3.2+): rounded rectangle and arrow attached to it. Both paths are merged and filled with solid color. The float value representing slider knob position is assigned to a property and cached as a string used by drawRect. The popup-view is added as subview upon UISlider subclass initialization.

- (void)drawRect:(CGRect)rect {
    // Set the fill color
	[[UIColor colorWithWhite:0 alpha:0.8] setFill];
    // Create the path for the rounded rectanble
    CGRect roundedRect = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width, self.bounds.size.height * 0.8);
    UIBezierPath *roundedRectPath = [UIBezierPath bezierPathWithRoundedRect:roundedRect cornerRadius:6.0];
    // Create the arrow path
    UIBezierPath *arrowPath = [UIBezierPath bezierPath];
    CGFloat midX = CGRectGetMidX(self.bounds);
    CGPoint p0 = CGPointMake(midX, CGRectGetMaxY(self.bounds));
    [arrowPath moveToPoint:p0];
    [arrowPath addLineToPoint:CGPointMake((midX - 10.0), CGRectGetMaxY(roundedRect))];
    [arrowPath addLineToPoint:CGPointMake((midX + 10.0), CGRectGetMaxY(roundedRect))];
    [arrowPath closePath];
    // Attach the arrow path to the rounded rectangle
    [roundedRectPath appendPath:arrowPath];
    [roundedRectPath fill];
    // Draw the text
    if (self.text) {
        [[UIColor colorWithWhite:1 alpha:0.8] set];
        CGSize s = [_text sizeWithFont:self.font];
        CGFloat yOffset = (roundedRect.size.height - s.height) / 2;
        CGRect textRect = CGRectMake(roundedRect.origin.x, yOffset, roundedRect.size.width, s.height);
        [_text drawInRect:textRect


This post shows how you can create a UISlider which shows which value is set while you move the slider’s knob. It is a lightweight and can be used as drop-in replacement wherever you used UISlider view before. However there is a room for improvements and customizations. You can use the code in your own project and modify it as you like.

Check it out on GitHub or download Xcode project:

{facebook-share} Bookmark and Share