You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter:如何随PageView滚动进度动态动画值(非仅onPageChanged)

How to Animate Elements During Page Scroll (Not Just on Page Change)

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 from
  • positionOffset: 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’s currentPageOffset to drive animations via modifiers. For SwiftUI, use ScrollViewReader or a custom Pager component to track progress.

内容的提问来源于stack exchange,提问作者Khamp3r

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 22:42:36