Flutter动画滚动插件animation_scroller的使用

Flutter动画滚动插件animation_scroller的使用

环境

Flutter 2.10.4  Dart >=2.16.2 <3.0.0

示例

介绍

// "Value" Scrolls to the bottom part.
_scrollController.widgetBuild(context, "Value", _scrollController.duration);

完整代码示例

import 'package:animation_scroller/animation_scroller.dart';
import 'package:flutter/material.dart';

class AnimationScroller extends ScrollController {
  /// Returns [value] plus 1.
  int addOne(int value) => value + 1;

  bool? initFlg;
  bool? animationFlg;
  int? durationValue;
  double? scrollOffset;
  double? keyboardHeight;
  double? _animationValue;
  double? _containerValue;
  double? _maxScrollExtent;

  /// Notify logic of scroll status.
  scrollState(ScrollNotification scrollNotification, double maxScrollExtent, double containerValue) {
    /// Check the status of scrollNotification.
    if (scrollNotification is ScrollStartNotification) {
    } else if (scrollNotification is ScrollUpdateNotification) {
    } else if (scrollNotification is ScrollEndNotification) {
      scrollOffset = position.maxScrollExtent;
      bool aFlg = (animationFlg ?? false);

      /// Judgment by scroll amount.
      _maxScrollExtent = maxScrollExtent;
      if (_maxScrollExtent == containerValue && aFlg) {
        animationFlg = false;
      }
    }
  }

  /// Initialization of each value.
  reset() {
    initFlg = true;
    durationValue = 0;
    scrollOffset = 0.0;
    keyboardHeight = 0.0;
    _animationValue = 0.0;
    _containerValue = 0.0;
    _maxScrollExtent = 0.0;
    jumpTo(0.0);
    animationFlg = false;

  }

  /// Bind with a widget.
  widgetBuild(BuildContext context, double containerValue, int duration) {
    bool iFlg = (initFlg ?? false);
    bool aFlg = (animationFlg ?? false);
    double kValue = (keyboardHeight ?? 0.0);
    double cValue = (_containerValue ?? 0.0);
    double offsetValue = (scrollOffset ?? 0.0);

    /// Scroll judgment.
    if (aFlg) {
      /// Substitute keyboard height.
      kValue = kValue <= MediaQuery.of(context).viewInsets.bottom
          ? MediaQuery.of(context).viewInsets.bottom
          : kValue;

      /// Substitute scroll amount.
      scrollOffset = (scrollOffset ?? 0.0) <= position.maxScrollExtent
          ? position.maxScrollExtent
          : (scrollOffset ?? 0.0);

      /// Scroll judgment
      if (offsetValue > cValue && iFlg) {
        animationFlg = false;

        /// Scroll animation method
        _animationLogic(duration);
      } else if (!iFlg) {
        /// Scroll animation method
        _animationLogic(duration);
      }

      _containerValue = containerValue;
    }
  }

  /// Speed set and flg check.
  speedCheck(FocusNode focusNode, int value) {
    /// Check focusNode state.
    switch (focusNode.hasFocus) {
      case true:
        durationValue = value;
        animationFlg = true;
        break;
    }
  }

  /// Scroll animation.
  _animationLogic(int duration) {
    Future(() {
      double offsetValue = (scrollOffset ?? 0.0);
      double cValue = (_containerValue ?? 0.0);

      /// Judgment by scroll amount.
      if (offsetValue > cValue) {
        /// Substitute the amount of animation.
        _animationValue = offsetValue - cValue;
        double aValue = (_animationValue ?? 0.0);
        animateTo(aValue,
            duration: Duration(milliseconds: duration), curve: Curves.linear);
      }
    });
  }
}

使用说明

在示例中,点击文本框会滚动到指定位置。

主要代码解析

初始化和重置

// 初始化各变量
reset() {
  initFlg = true;
  durationValue = 0;
  scrollOffset = 0.0;
  keyboardHeight = 0.0;
  _animationValue = 0.0;
  _containerValue = 0.0;
  _maxScrollExtent = 0.0;
  jumpTo(0.0); // 滚动到顶部
  animationFlg = false;
}

绑定到控件

// 绑定到控件
widgetBuild(BuildContext context, double containerValue, int duration) {
  bool iFlg = (initFlg ?? false);
  bool aFlg = (animationFlg ?? false);
  double kValue = (keyboardHeight ?? 0.0);
  double cValue = (_containerValue ?? 0.0);
  double offsetValue = (scrollOffset ?? 0.0);

  // 滚动判断
  if (aFlg) {
    // 替换键盘高度
    kValue = kValue <= MediaQuery.of(context).viewInsets.bottom
        ? MediaQuery.of(context).viewInsets.bottom
        : kValue;

    // 替换滚动量
    scrollOffset = (scrollOffset ?? 0.0) <= position.maxScrollExtent
        ? position.maxScrollExtent
        : (scrollOffset ?? 0.0);

    // 滚动判断
    if (offsetValue > cValue && iFlg) {
      animationFlg = false;

      // 滚动动画方法
      _animationLogic(duration);
    } else if (!iFlg) {
      // 滚动动画方法
      _animationLogic(duration);
    }

    _containerValue = containerValue;
  }
}

设置速度并检查标志

// 设置速度并检查标志
speedCheck(FocusNode focusNode, int value) {
  // 检查焦点状态
  switch (focusNode.hasFocus) {
    case true:
      durationValue = value;
      animationFlg = true;
      break;
  }
}

滚动动画逻辑

// 滚动动画逻辑
_animationLogic(int duration) {
  Future(() {
    double offsetValue = (scrollOffset ?? 0.0);
    double cValue = (_containerValue ?? 0.0);

    // 判断滚动量
    if (offsetValue > cValue) {
      // 替换动画量
      _animationValue = offsetValue - cValue;
      double aValue = (_animationValue ?? 0.0);
      animateTo(aValue,
          duration: Duration(milliseconds: duration), curve: Curves.linear);
    }
  });
}

更多关于Flutter动画滚动插件animation_scroller的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter动画滚动插件animation_scroller的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,animation_scroller 是一个用于在 Flutter 中实现复杂滚动动画的插件。它通过预定义的动画曲线和配置,可以帮助开发者轻松实现平滑且吸引人的滚动效果。以下是一个简单的代码示例,展示了如何使用 animation_scroller 插件来实现一个带有动画滚动的页面。

首先,确保你已经在 pubspec.yaml 文件中添加了 animation_scroller 依赖:

dependencies:
  flutter:
    sdk: flutter
  animation_scroller: ^x.y.z  # 请替换为最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来是一个示例代码,展示了如何使用 animation_scroller 来实现滚动动画:

import 'package:flutter/material.dart';
import 'package:animation_scroller/animation_scroller.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Animation Scroller Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ScrollerDemo(),
    );
  }
}

class ScrollerDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Animation Scroller Demo'),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            // 使用 AnimationScrollerController 和 ScrollPositionListener 包装内容
            AnimationScrollerController(
              controller: ScrollController(),
              duration: Duration(seconds: 2),
              curve: Curves.easeInOutQuad,
              child: ScrollPositionListener(
                child: Column(
                  children: <Widget>[
                    // 第一个动画元素
                    AnimatedBuilder(
                      animation: AnimationScroller.of(context).position,
                      child: Container(
                        height: 200,
                        color: Colors.red,
                        child: Center(child: Text('Animated Box 1')),
                      ),
                      builder: (context, child, position) {
                        final double opacity = position.pixels / 300; // 假设滚动300像素时完全显示
                        return Opacity(
                          opacity: opacity.clamp(0.0, 1.0),
                          child: child,
                        );
                      },
                    ),

                    // 添加一些填充内容,以便滚动
                    SizedBox(height: 400),

                    // 第二个动画元素
                    AnimatedBuilder(
                      animation: AnimationScroller.of(context).position,
                      child: Container(
                        height: 200,
                        color: Colors.green,
                        child: Center(child: Text('Animated Box 2')),
                      ),
                      builder: (context, child, position) {
                        final double translateY = -50 * (1 - (position.pixels / 600).clamp(0.0, 1.0)); // 假设滚动600像素时完成上升动画
                        return Transform.translate(
                          offset: Offset(0, translateY),
                          child: child,
                        );
                      },
                    ),

                    // 添加更多填充内容,以便滚动
                    SizedBox(height: 800),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

在这个示例中:

  1. 我们创建了一个 SingleChildScrollView,其中包含多个动画元素。
  2. 使用 AnimationScrollerControllerScrollPositionListener 包装这些动画元素,以便可以监听滚动位置并应用动画。
  3. 对于每个动画元素,我们使用 AnimatedBuilder 来根据滚动位置动态调整其属性(如透明度和位置)。

请注意,上述代码中的动画参数(如滚动距离和动画曲线)可以根据实际需求进行调整。这个示例主要展示了如何使用 animation_scroller 插件的基本结构和概念。

回到顶部