Luke
Luke

Reputation: 9700

Animate UITableView index, a la Apple Music?

Simple question:

Apple Music's table views only show an A-Z section index on the right edge once they've been scrolled down past a certain threshold, and that index animates in and out nicely.

I've been able to trigger the appearing / disappearing behaviour with the code below, but the index just pops in and out, there's no animation, and I can't find any way to get one to show up.

func sectionIndexTitlesForTableView(tableView: UITableView) -> [AnyObject]! {
    if tableView.contentOffset.y > 88 {
        return DataManager.sharedManager.frc!.sectionIndexTitles
    } else {
        return []
    }
}

func scrollViewDidScroll(scrollView: UIScrollView) {
    tableView.reloadSectionIndexTitles()
}

This basically means each time the scroll view ticks, it'll reload the section indexes, then conditionally hide or show the index based on the offset of the table. As I say, it works, but it doesn't animate the index, and I'd really love that functionality if possible.

Upvotes: 0

Views: 379

Answers (3)

mindz_eye
mindz_eye

Reputation: 73

I would not suggest playing with private classes, since it can easily break in a future OS release. I've implemented a custom control for the exact purpose. It mimics the native table index appearance while providing much more customization capabilities. Check https://github.com/mindz-eye/MYTableViewIndex for details.

Upvotes: 0

wm.hass
wm.hass

Reputation: 36

Seems like it is not possible to do that, ate least apple doesn't provide any API to animate the section index view. I am able to slide in/out the indexes, but it doesn't resize the cells' contentView.

When you animate the section index view, right after the animation it comes back to its initial position. So I am basically setting the color to clearColor/black when hidden/visible.

I am not sure if apple approves this code since it's kind of using undocumented APIs

- (UIView *)indexTitlesView {
    NSArray *subViews = [self.tableView subviews];
    for (UIView *view in subViews) {
        if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewIndex"]) {
            return view;
        }
    }
    return nil;
}

- (void)slideIndexTitlesViewIn {
    UIView *indexTitlesView = [self indexTitlesView];

    CABasicAnimation *contentPositionAnimation = [CABasicAnimation animationWithKeyPath:@"position.x"];
    contentPositionAnimation.fromValue = @(CGRectGetWidth(indexTitlesView.frame));
    contentPositionAnimation.toValue = @(0);
    contentPositionAnimation.additive = YES;
    contentPositionAnimation.duration = 0.3;
    contentPositionAnimation.delegate = self;
    contentPositionAnimation.removedOnCompletion = NO;
    contentPositionAnimation.fillMode = kCAFillModeForwards;

    [indexTitlesView.layer removeAllAnimations];
    [indexTitlesView.layer addAnimation:contentPositionAnimation forKey:@"slideInAnimation"];

    self.tableView.sectionIndexColor = [UIColor blackColor];
}

- (void)slideIndexTitlesViewOut {
    UIView *indexTitlesView = [self indexTitlesView];

    CABasicAnimation *contentPositionAnimation = [CABasicAnimation animationWithKeyPath:@"position.x"];
    contentPositionAnimation.fromValue = @(0);
    contentPositionAnimation.toValue = @(CGRectGetWidth(indexTitlesView.frame));
    contentPositionAnimation.additive = YES;
    contentPositionAnimation.duration = 0.3;
    contentPositionAnimation.delegate = self;
    contentPositionAnimation.removedOnCompletion = NO;
    contentPositionAnimation.fillMode = kCAFillModeForwards;

    [indexTitlesView.layer removeAllAnimations];
    [indexTitlesView.layer addAnimation:contentPositionAnimation forKey:@"slideOutAnimation"];
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    UIView *indexTitlesView = [self indexTitlesView];
    NSArray *keys = [indexTitlesView.layer animationKeys];
    for (NSString *key in keys) {
        if ([indexTitlesView.layer animationForKey:key] == anim) {
            if ([key isEqualToString:@"slideOutAnimation"] && flag == YES) {
                self.tableView.sectionIndexColor = [UIColor clearColor];
            }
            [indexTitlesView.layer removeAllAnimations];
            return;
        }
    }
}

Upvotes: 1

Tyler
Tyler

Reputation: 34

Just use the animateWithDuration() method set the alpha value to zero and then animate it in by setting the value to 1

Upvotes: 0

Related Questions