Flutter:如何随PageView滚动进度动态动画值(非仅onPageChanged)
Awesome question! This is exactly the kind of subtle, polished animation that makes apps feel intuitive—just like how Snapchat handles its top search bar during swipes. The key is to track the real-time scroll progress between pages (not just when a page fully changes) and use that value to drive your animations. Let’s break down how to implement this on the two main mobile platforms:
Android: Using ViewPager2
ViewPager2 gives you direct access to scroll progress via its OnPageChangeCallback—specifically the onPageScrolled method, which fires every frame during a swipe.
Step 1: Set up your views
First, reference your ViewPager2 and the element you want to animate (e.g., a search bar):
val viewPager = findViewById<ViewPager2>(R.id.your_view_pager) val topSearchBar = findViewById<View>(R.id.your_search_bar)
Step 2: Track scroll progress and animate
Attach a callback to capture scroll updates, then calculate and apply your animation value (in this case, opacity):
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageScrolled( position: Int, positionOffset: Float, positionOffsetPixels: Int ) { super.onPageScrolled(position, positionOffset, positionOffsetPixels) // positionOffset ranges from 0 (fully on current page) to 1 (fully on next page) // We'll fade the search bar out as we swipe away from the current page val targetOpacity = 1f - positionOffset topSearchBar.alpha = targetOpacity // Bonus: Animate translation too, like Snapchat might val targetY = -positionOffset * 20 // Move up 20dp as we swipe topSearchBar.translationY = targetY } })
position: The index of the page you're swiping away frompositionOffset: A float between 0 and 1 that tells you how far along you are in the swipe to the next page
Step 3: Smooth out performance
Directly setting alpha or translationY in onPageScrolled works for most cases, but if you notice jank, wrap the updates in postOnAnimation to ensure they run on the main thread's animation frame:
topSearchBar.postOnAnimation { topSearchBar.alpha = targetOpacity }
iOS: Using UIPageViewController
On iOS, you’ll need to access the underlying UIScrollView of your UIPageViewController to track scroll progress.
Step 1: Get the scroll view
In your UIPageViewController subclass, grab the scroll view during setup:
override func viewDidLoad() { super.viewDidLoad() // Find the scroll view in the page view controller's subviews if let scrollView = view.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView { scrollView.delegate = self } }
Step 2: Track scroll progress and animate
Implement the UIScrollViewDelegate method to get real-time scroll updates:
extension YourPageViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { let pageWidth = scrollView.frame.width let currentOffset = scrollView.contentOffset.x // Calculate progress between pages (0 to 1 per swipe) let swipeProgress = currentOffset.truncatingRemainder(dividingBy: pageWidth) / pageWidth // Animate the search bar's opacity topSearchBar.alpha = 1 - swipeProgress // Add translation for extra polish topSearchBar.transform = CGAffineTransform(translationX: 0, y: -swipeProgress * 20) } }
General Tips for Any Platform
- Customize the animation logic: You’re not limited to opacity—use the scroll progress to animate scale, rotation, or any view property.
- Handle edge cases: Add checks to avoid weird behavior when scrolling past the first/last page (most page controllers clamp scrolling, but it’s safe to validate values).
- Keep it lightweight: Avoid heavy calculations in the scroll callback—this runs every frame, so keep operations simple to maintain 60fps.
Pro tip: If you’re using Jetpack Compose (Android) or SwiftUI (iOS), the approach is similar. For Compose, use
PagerState’scurrentPageOffsetto drive animations via modifiers. For SwiftUI, useScrollViewReaderor a customPagercomponent to track progress.
内容的提问来源于stack exchange,提问作者Khamp3r

