We develop Stories mechanics — disappearing content — in mobile apps for iOS, Android, and cross-platform.
This is a non-trivial UI pattern: progress bars with 60 FPS animation, tap navigation, hold to pause, swipe down to close, media preloading without delays, and a 24-hour server-side timer. A mistake in any of these elements ruins the user experience.
Our experience — 10+ years of mobile development, more than 50 delivered projects. We will assess your project.
How we implement progress bars and navigation
Horizontal progress bars at the top are UIView with frame.width animation via CADisplayLink (iOS) or ValueAnimator (Android). CADisplayLink provides 60/120 FPS screen synchronization — the animation is smooth.
Using Timer.scheduledTimer is not recommended: it stutters, especially under load. The duration of one story is usually 5–7 seconds for photos, and the clip length for video (but no more than 15 seconds).
We synchronize the video progress bar with AVPlayer.currentTime() via addPeriodicTimeObserver, not with a system timer.
Navigation: tap the right half of the screen — next story, left half — previous. UITapGestureRecognizer with a check location.x > bounds.width / 2.
Hold — UILongPressGestureRecognizer with minimumPressDuration: 0.1: on .began we pause the animation and AVPlayer, on .ended — resume. Swipe down to close — interactive dismiss via UIPanGestureRecognizer.
Scaling and moving the screen following the gesture (transform), on release — either full close (dismiss), or return (UIViewPropertyAnimator).
Why is media preloading critical?
Delay when switching stories is the main UX bug. The user taps — and waits 1–2 seconds while a photo or video loads. The right solution: preload the next 2–3 stories. For photos — SDWebImage.prefetchURLs() or Kingfisher ImagePrefetcher.
For video — AVAsset.loadValuesAsynchronously(forKeys: ["playable"]) + create the AVPlayerItem in advance, and don't start the AVPlayer until display.
On Android — Coil ImageLoader.enqueue(ImageRequest) for photo preloading, ExoPlayer with ConcatenatingMediaSource for video: add the next item to the queue, and ExoPlayer preloads the buffer.
Cache preloaded assets in memory (not only on disk) — re-viewing a story within the session must be instant.
Creating stories: from photo to video
Photo — PHPickerViewController + optional editor (text, stickers). Text overlay on image: UITextView over UIImageView, when saving — merge into UIGraphicsImageRenderer. Stickers — UIView with UIPanGestureRecognizer + UIPinchGestureRecognizer + UIRotationGestureRecognizer.
Video — recording via AVCaptureSession directly in the stories camera (like in Instagram/Snapchat) or selecting from the gallery. Recording with a 15-second limit — AVCaptureMovieFileOutput.maxRecordedDuration. Hold the button to record, release to stop.
After creation — upload in the background. Stories appears in the feed immediately with a placeholder, and is replaced with real content after loading.
How does the disappearing timer work?
The 24-hour timer is server-side, not client-side. The client simply requests the list of current stories. The server filters by created_at + 24h < now. On the client, for stories already loaded from the cache, we check expiresAt when opening.
If it has expired, we don't show the cached version and request the server (or delete it from local storage). Views are recorded on the server via a separate API request after the story is displayed.
We batch the view records: instead of one request per view, we accumulate them over the session and send them when the app is minimized or every 30 seconds.
Common mistakes when implementing Stories
| Mistake | Consequence | Solution |
|---|---|---|
Using Timer for the progress bar |
Choppy animation, desync with video | CADisplayLink on iOS, ValueAnimator on Android |
| Loading media on the fly | Delays when switching | Preloading the next 2-3 stories |
| No in-memory cache | Repeated downloads when returning | Caching in NSCache or LruCache |
Ignoring expiresAt on the client |
Showing outdated stories | Checking the time before display |
| Individual view requests | Load on the server | Batching once every 30 seconds |
What is included in the work
- Documentation (API schemas, flow diagrams)
- Source code with comments
- Access to the repository, App Store Connect / Google Play Console
- Integration with your backend (REST/GraphQL)
- Testing on real devices (iOS 15+, Android 10+)
- Post-release support for 1 month
Timeline and cost
Viewing stories with progress bars, preloading, navigation, and an expiration timer — 3–4 days. Creation with camera, text, and stickers + upload — another 2–3 days. Cost is calculated individually after analyzing your project. Contact us — get a consultation and a preliminary estimate.
| Component | Time (days) |
|---|---|
| Viewing mechanics (progress bars, gestures, timer) | 3-4 |
| Preloading and caching media | 2-3 |
| Stories creation (camera, editor, upload) | 2-3 |
| Backend integration and testing | 2-3 |
| Total | 7-10 |
You can read more about the mechanics of stories in App Store Review Guidelines (Section 4.2 and 5.1) and Google Play documentation.
Our team has 10+ years of experience in mobile development; we guarantee quality and adherence to deadlines. Request stories development for your app — we’ll estimate your project within 1 day.







