6

I'm using a horizontal UIScrollView, and I want a background color transition depending on the x value of the content offset.

Example: The width of UIScrollView is 640px. When the content offset is equal to 0px, the background color must be red. When the content offset is 320 px, the background must be yellow. But the most important part is, when the UIScrollview is between 0px and 320px the background color must be between red and yellow.

Hint: The twitter app for iOS has the same animation when you swipe to the left from a search. The the label on the navigation slightly disappears.

Berendschot
  • 2,834
  • 1
  • 17
  • 42

3 Answers3

20

You need to create the colour depending on the offset percentage.

The easiest way to create a shift between colours like this is to use the HSB colour space.

Also, this isn't an animation. The "animation" effect is given to you by the scrollview. You just need to set the colour every time the scroll view changes.

In the delegate method you could do something like this.

Edit to make more flexible

// this just calculates the percentages now and passes it off to another method.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    // vertical
    CGFloat maximumVerticalOffset = scrollView.contentSize.height - CGRectGetHeight(scrollView.frame);
    CGFloat currentVerticalOffset = scrollView.contentOffset.y;

    // horizontal
    CGFloat maximumHorizontalOffset = scrollView.contentSize.width - CGRectGetWidth(scrollView.frame);
    CGFloat currentHorizontalOffset = scrollView.contentOffset.x;

    // percentages
    CGFloat percentageHorizontalOffset = currentHorizontalOffset / maximumHorizontalOffset;
    CGFloat percentageVerticalOffset = currentVerticalOffset / maximumVerticalOffset;

    [self scrollView:scrollView didScrollToPercentageOffset:CGPointMake(percentageHorizontalOffset, percentageVerticalOffset)];
}

// this just gets the percentage offset.
// 0,0 = no scroll
// 1,1 = maximum scroll
- (void)scrollView:(UIScrollView *)scrollView didScrollToPercentageOffset:(CGPoint)percentageOffset
{
    UIColor *HSBColor = [self HSBColorForOffsetPercentage:percentageOffset.x];

    UIColor *RGBColor = [self RGBColorForOffsetPercentage:percentageOffset.x];
}

// HSB color just using Hue
- (UIColor *)HSBColorForOffsetPercentage:(CGFloat)percentage
{
    CGFloat minColorHue = 0.0;
    CGFloat maxColorHue = 0.2; // this is a guess for the yellow hue.

    CGFloat actualHue = (maxColorHue - minColorHue) * percentage + minColorHue;

    // change these values to get the colours you want.
    // I find reducing the saturation to 0.8 ish gives nicer colours.
    return [UIColor colorWithHue:actualHue saturation:1.0 brightness:1.0 alpha:1.0];
}

// RGB color using all R, G, B values
- (UIColor *)RGBColorForOffsetPercentage:(CGFloat)percentage
{
    // RGB 1, 0, 0 = red
    CGFloat minColorRed = 1.0;
    CGFloat minColorGreen = 0.0;
    CGFloat minColorBlue = 0.0;

    // RGB 1, 1, 0 = yellow
    CGFloat maxColorRed = 1.0;
    CGFloat maxColorGreen = 1.0;
    CGFloat maxColorBlue = 0.0;

    // if you have specific beginning and end RGB values then set these to min and max respectively.
    // it should even work if the min value is greater than the max value.

    CGFloat actualRed = (maxColorRed - minColorRed) * percentage + minColorRed;
    CGFloat actualGreen = (maxColorGreen - minColorGreen) * percentage + minColorGreen;
    CGFloat actualBlue = (maxColorBlue - minColorBlue) * percentage + minColorBlue;

    return [UIColor colorWithRed:actualRed green:actualGreen blue:actualBlue alpha:1.0];
}

I don't know how the RGB method will perform on mid values. It may go brown in the middle etc... but you can play around.

This should give you an idea of how to animate ANYTHING using the scroll view as a way to control it.

Using this method you can control the opacity, size, rotation, font size, etc... You can even combine multiple things (like I did with RGB).

Fogmeister
  • 70,181
  • 37
  • 189
  • 274
1

Inspired by @Fogmeister's answer I put the pieces together in swift.

extension UIColor {
    static func color(between start: UIColor, and end: UIColor, percentage: CGFloat) -> UIColor {
        let startRGB = start.rgba
        let stopRGB = end.rgba

        let red: CGFloat = (stopRGB.red - startRGB.red) * percentage + startRGB.red
        let green: CGFloat = (stopRGB.green - startRGB.green) * percentage + startRGB.green
        let blue: CGFloat = (stopRGB.blue - startRGB.blue) * percentage + startRGB.blue
        let alpha: CGFloat = (stopRGB.alpha - startRGB.alpha) * percentage + startRGB.alpha

        return UIColor(red: red, green: green, blue: blue, alpha: alpha)
    }

    var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
        var red: CGFloat = 0
        var green: CGFloat = 0
        var blue: CGFloat = 0
        var alpha: CGFloat = 0
        getRed(&red, green: &green, blue: &blue, alpha: &alpha)
        return (red, green, blue, alpha)
    }
}

Now you can do something like this:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let offset = scrollView.contentOffset.y
    let scrolledDistance = offset + scrollView.contentInset.top
    let progress = max(0, min(1, scrolledDistance / scrollView.contentSize.height))

    someLabel.textColor = .color(between: .red, and: .green, percentage: progress)
}

Warning: This implementation will trigger swiftlints large_tuple rule. But you can disable, simply add ' - large_tuple' into disabled_rules section.

Apoc
  • 687
  • 1
  • 9
  • 14
-3

In your scrollView delegate try something like this:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
    CGPoint a = self.mainScrollView.contentOffset;
    if(a.x >= 320){
        [UIView animateWithDuration:0.5 animations:^{
            [self.view setBackgroundColor:[UIColor redColor]];
        }];
    }
    else{
        [UIView animateWithDuration:0.5 animations:^{
            [self.view setBackgroundColor:[UIColor yellowColor]];
        }];
    }
}
Istvan
  • 1,587
  • 1
  • 10
  • 16
  • Why the downvote? Even if the code above is not exactly correct to the specific needs expressed in the question, it does hint at what the asker could try to get his color logic working. – Daniel Saidi Oct 02 '14 at 11:10
  • 3
    Not my down vote. But... This will not create the effect that the person asking the question is looking for. If the scrollView is at 319 offset then this will animate to yellow. It should be almost entirely red. Also, this won't give the half way between red and yellow effect that he's looking for either. Plus, the animation is unnecessary here too. – Fogmeister Oct 02 '14 at 11:18