iPhone "slide to unlock" animation

Viewed 32827

Any ideas as to how Apple implemented the "slide to unlock" (also, "slide to power off" is another identical example) animation?

I thought about some sort of animating mask - but masking is not available on the iPhone OS for performance reasons.

Is there some private API effect (like SuckEffect) that they might have used? A spotlight type of effect? Some Core Animation thing?

Edit: It's definitely not a series of stills. I've seen examples of being edit a plist value or something and customize the string on jailbroken iphones.

13 Answers

You can use the kCGTextClip drawing mode to set the clipping path and then fill with a gradient.

// Get Context
CGContextRef context = UIGraphicsGetCurrentContext();
// Set Font
CGContextSelectFont(context, "Helvetica", 24.0, kCGEncodingMacRoman);
// Set Text Matrix
CGAffineTransform xform = CGAffineTransformMake(1.0,  0.0,
                                                0.0, -1.0,
                                                0.0,  0.0);
CGContextSetTextMatrix(context, xform);
// Set Drawing Mode to set clipping path
CGContextSetTextDrawingMode (context, kCGTextClip);
// Draw Text
CGContextShowTextAtPoint (context, 0, 20, "Gradient", strlen("Gradient")); 
// Calculate Text width
CGPoint textEnd = CGContextGetTextPosition(context);
// Generate Gradient locations & colors
size_t num_locations = 3;
CGFloat locations[3] = { 0.3, 0.5, 0.6 };
CGFloat components[12] = { 
    1.0, 1.0, 1.0, 0.5,
    1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 0.5,
};
// Load Colorspace
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
// Create Gradient
CGGradientRef gradient = CGGradientCreateWithColorComponents (colorspace, components,
                                                              locations, num_locations);
// Draw Gradient (using clipping path
CGContextDrawLinearGradient (context, gradient, rect.origin, textEnd, 0);
// Cleanup (exercise for reader)

Setup an NSTimer and vary the values in locations, or use CoreAnimation to do the same.

Here's a SwiftUI version:

public struct Shimmer: AnimatableModifier {

    private let gradient: Gradient

    @State private var position: CGFloat = 0

    public var animatableData: CGFloat {
        get { position }
        set { position = newValue }
    }

    private let animation = Animation
        .linear(duration: 2)
        .delay(1)
        .repeatForever(autoreverses: false)

    init(sideColor: Color = Color(white: 0.25), middleColor: Color = .white) {
        gradient = Gradient(colors: [sideColor, middleColor, sideColor])
    }

    public func body(content: Content) -> some View {
        LinearGradient(
            gradient: gradient,
            startPoint: .init(x: position - 0.2 * (1 - position), y: 0.5),
            endPoint: .init(x: position + 0.2 * position, y: 0.5)
        )
        .mask(content)
        .onAppear {
            withAnimation(animation) {
                    position = 1
                }
        }
    }
}

Use it like this:

Text("slide to unlock")
    .modifier(Shimmer())

Maybe it's just a rendered-out animation - you know, a series of stills played one after another. Not necessarily a dynamic effect.

Update: Never mind, the video DrJokepu posted proved it's dynamically generated.

Related