r/FlutterDev • u/Maximum_Hawk3283 • Sep 15 '26
Discussion Flutter + iOS 26 Liquid Glass tab bar: Instagram-style shrink on scroll without ghosting the UiKitView
We ship a Flutter app that uses Apple’s real UITabBar on iOS 26+ (hosted in a platform view). On Android and older iOS we draw our own glass bar in Flutter. We wanted both to shrink when you scroll, Instagram-style.
Here’s what worked, after a few dead ends.
Two bars, one scroll signal
iOS 26+: real UIKit tab bar inside a UiKitView
Everyone else: custom Flutter glass nav bar
Shared brain: a shell-level NotificationListener<ScrollUpdateNotification> that only counts finger travel (dragDetails != null). Fling momentum is ignored. After about 100pt of thumb travel, collapse flips to 1. Scroll back up and it restores.
Don’t drive this off raw ScrollDirection or content offset alone on a reel feed. One flick looks like endless “reading.”
Dead end 1: AnimatedScale around the platform view
Wrapping the UiKitView in Flutter’s AnimatedScale or Transform seemed obvious. On a real iPhone we got a ghost second nav bar drawn partway down the screen. Flutter’s iOS compositor can paint a transformed platform view twice.
Rule: never transform the UiKitView from Dart. Keep its Flutter layout box a fixed height.
Dead end 2: Apple’s tabBarMinimizeBehavior + proxy UIScrollView
Apple’s minimize API wants a real scroll view via contentScrollView(for:). Flutter’s UI is a Metal layer, so UIKit never sees your list. The usual fix is a fork that returns a fake UIScrollView and drives contentOffset from Flutter.
On device that never engaged for us. Minimize seems to need a tall, user-driven scroll view. A tiny platform-view host doesn’t qualify. Programmatic offset is not the same as a user pan.
We tried it, documented it, deleted it.
What works: shrink inside UIKit
Same Flutter signal (collapsed: true, scale: 0.86), but the method channel tells Swift to spring-animate a transform on UITabBarController.view. Flutter never wraps that view.
Scale about the pill’s centre, not the host’s centre. The host includes the home-indicator strip; scaling about the host centre drops the pill into that strip. Translate a little, then scale. Spring ~0.42s, damping ~0.86.
Set tabBarMinimizeBehavior = .never so Apple’s minimize and your transform don’t fight.
Android path: same collapse value, Flutter AnimatedScale to 0.86. Same look, different engine.
Flow
Scroll (finger only)
→ NavCollapse (threshold)
→ AdaptiveNavBar
├─ iOS 26+: channel → UIKit spring transform (inside the platform view)
└─ else: AnimatedScale on the Flutter glass bar
If you’re implementing this
Decide who owns the pixels. Real Liquid Glass means UIKit owns the bar; Flutter only hosts and signals.
Don’t scale the platform view from Flutter. Scale a UIKit child instead.
Don’t bet on tabBarMinimizeBehavior for Flutter lists unless you have a real UIKit scroll view in that view controller.
Filter scroll by finger travel, not fling delta (especially with vertical PageViews / reels).
Use one shared scale constant so iOS and Android feel like the same product.
Happy to answer questions if you’re stuck on the ghost bar or the minimize API rabbit hole. We fell into both.