Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fade in/out UIScrollView's content like Mobile Safari does in its tab

NOTE: I added my new solution at the UPDATE answer below.

I try to recreate the effects we saw in Mobile Safari's tab on iPhone/iPod touch.

Basically, it's a UIScrollView that holds 4 reusable UIView (acting like ring buffer), and scrolls horizontally. When scrolling, the UIView's opacity will fade in/out seamlessly with offset.

Currently, I do all the dirty job in - (void)scrollViewDidScroll:(UIScrollView *)scrollView. Such as getting the contentOffset from UIScrollView, determine the pageingation, calculate the delta between contentOffset and each UIView positions, and decide/set the alpha value of each UIView at the moment when scrollViewDidScroll: was called.

And it works, performance is okay, everything runs smoothly, but the only problem is too much calculating.

I tried UIView's beginAnimations: and commitAnimations:, but it's useless in scrollViewDidScroll:, since 1) the new alpha value still have to be calculate by myself, and 2) scrollViewDidScroll: kept called when scrolling, it's meaningless to do the animation here. Is there any way to rewrite this part with Core Animation? So I don't have to do the math myself on alpha value of each UIView, instead, I can left whole works to Core Animation.

like image 928
digdog Avatar asked May 17 '09 18:05

digdog


People also ask

Does Safari not support over scroll?

May 2, 2016 UPDATE 2017.12: For non-Safari browsers (e.g. Chrome, Firefox) you can use overscroll-behavior to solve exactly this. Simply apply overscroll-behavior-y: none; on html, body and be done with it. Safari however does not support it …

Does Safari support overscroll-behavior?

Bramus! May 2, 2016 UPDATE 2017.12: For non-Safari browsers (e.g. Chrome, Firefox) you can use overscroll-behavior to solve exactly this. Simply apply overscroll-behavior-y: none; on html, body and be done with it. Safari however does not support it …

Do you have WebKit bug #176454 on safari?

Follow Webkit bug #176454 to stay up-to-date on support in Safari. Know this bouncy overscrolling behaviour that browsers have been doing whenever you reach the “edge” of the page its contents? Sometimes – in fullscreen apps for example – you’ll want to disable this.


2 Answers

UPDATE

I came up with another way to update alpha value of each page. When creating content view, I use KVO to addObserver with UIScrollView's contentOffset:

[self.scrollView addObserver:[self.contentViews objectAtIndex:i] 
                  forKeyPath:@"contentOffset" 
                     options:NSKeyValueObservingOptionNew
                     context:@selector(updateAlpha:)];

So that each of my contentViews will get the message when contentOffset changed:

- (void)observeValueForKeyPath:(NSString *)keyPath 
                      ofObject:(id)object 
                        change:(NSDictionary *)change 
                       context:(void *)context {
    [self performSelector:(SEL)context withObject:change];
}

And my contentViews can do the calculation and animate by themselves when scrolling:

- (void)updateAlpha:(NSDictionary *)change {
    CGFloat offset = [[change objectForKey:NSKeyValueChangeNewKey] CGPointValue].x;
    CGFloat origin = [self frame].origin.x;
    CGFloat delta = fabs(origin - offset);

    [UIView beginAnimations:@"Fading" context:nil];
    if (delta < [self frame].size.width) {
        self.alpha = 1 - delta/self.frame.size.width*0.7;
    } else {
        self.alpha = 0.3;
    }
    [UIView commitAnimations];
}

Of course, you will need to remove the observer when you remove the content view from superview, and add them again when new content view created.

Hope this help to those who want to do the same.

like image 178
digdog Avatar answered Nov 15 '22 19:11

digdog


As you'll have noticed from how often scrollViewDidScroll: is called, UIScrollView doesn't simply fire and forget a Core Animation transition: it manually moves the bounds according to touches, acceleration, etc. There's no straightforward way to change this.

However, if you're being swamped by scroll events, you might try a trick like the following:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    NSTimeInterval timestamp = [[NSDate date] timeIntervalSince1970];
    if (timestamp - _savedTimestamp) < 0.1)
        return;
    _savedTimestamp = timestamp;

    // do the rest of your work here
}

H

like image 26
hatfinch Avatar answered Nov 15 '22 18:11

hatfinch