Imitation nuggets mobile app pull down loading dynamic effect.

Background & Introduction

I have been brushing the gold digging app, and every time I see the dynamic effect of the pull-down loading, I thought if I could copy one to see the effect. Through dozens of pull-down refresh, we can see that the dynamic effect is mainly composed of the following parts. (There may be more details, but only the main effects are achieved here)

  1. Start to pull down, gray nuggets logo appears;
  2. After pulling down to the bottom, remove the finger on the drop-down screen, and the Nuggets logo turns blue.
  3. Then the nuggets blue changed back to gray, and from gray to nuggets blue. Here is a linear gradient of a color from top to bottom.
  4. After turning completely blue, the background color of light blue gradually spreads from a point in the center to the left, right, and top edges of the drop-down screen;
  5. Drop down done, finished.

Project analysis

CupertinoSliverRefreshControl drop-down effect we use to realize the drop-down, here we didn’t use RefreshIndicator mainly because of his work and the Denver nuggets, CupertinoSliverRefreshControl this IOS – style of dynamic effect, and the nuggets are similar. I’m using an off-the-shelf example from the web as an initialization template.

First of all, we have to know where to implement the dynamic effect, CupertinoSliverRefreshControl provides a builder parameter, this parameter will distinguish between the various periods of the drop-down, refer to:

/// The current state of the refresh control.
///
/// Passed into the [RefreshControlIndicatorBuilder] builder function so
/// users can show different UI in different modes.
enum RefreshIndicatorMode {
  /// Initial state, when not being overscrolled into, or after the overscroll
  /// is canceled or after done and the sliver retracted away.
  inactive,

  /// While being overscrolled but not far enough yet to trigger the refresh.
  drag,

  /// Dragged far enough that the onRefresh callback will run and the dragged
  /// displacement is not yet at the final refresh resting state.
  armed,

  /// While the onRefresh task is running.
  refresh,

  /// While the indicator is animating away after refreshing.
  done,
}
Copy the code

From the above steps, we can make inactive, Drag, and Done display the gray nuggets logo and armed display the blue nuggets logo using the following code:

  static Widget buildJuejinSvg(Color color) {
    return Center(
      child: SvgPicture.asset(
        'assets/images/juejin.svg',
        color: color,
      ),
    );
  }
Copy the code

Next, we need to show steps 3 and 4 above, a gradient, and a scale effect. We can create a new Statelesswidget for the animation. This widget is responsible for making Tweens, defining each animation object, Provide a build() method to build the widget tree that we need to display for the drop-down refresh.

We will define two Animation objects, one for color gradient and the other for scale light blue to the edge of the screen.

Color gradient

From the grayLogo to the blueLogo, we use two SVG superimposed to achieve the effect, one grayLogo and one blueLogo on the bottom and one blueLogo on the top. BlueLogo uses ClipRect’s heightFactor parameter clipping, initializes heightFactor to 0 and gradually changes it to 1, thus achieving the following effect: GrayLogo renders by default, while blueLogo does not render because heightFactor is initially 0. Tween dynamic effect is used to change the 0 of heightFactor into 1, so that blueLogo completely covers the grayLogo below. The code is as follows:

// Animation object final animation <double> offsetForColorChanges; OffsetForColorChanges = Tween<double>(begin: 0.0, end: 1.0). Animate (Parent: controller, curve: Interval(0.0, 0.700, Curve: easeIn),),Copy the code
Widget tree widget _buildAnimation(BuildContext context, Widget child) { final sw = MediaQuery.of(context).size.width; C-21. Return Stack(children: [utils. buildJuejinSvg(Colors. Grey), toy (left: sw / 2-22.5, top: 11.5, child: ClipRect(Child: Align(alignment: Align. TopCenter, widthFactor: 1.0, heightFactor: offsetForColorChanges.value, child: Utils.buildJuejinSvg(Colors.blue), ), ), ), ], ); }Copy the code

Here, the Stack layout is used to overlay grayLogo and blueLogo.

Scale Light blue to edge of screen

The color gradient is followed by a light blue scale to the edge of the screen. Here we define an animation object:

final Animation<double> scale; Scale = Tween<double>(begin: 0.0, end: 1.0). Animate (CurvedAnimation(parent: controller, curve: Interval(0.700, 1.00, Curve: easeIn),),Copy the code

To scale a widget, we can use the ScaleTransition class, which provides an animation as an argument to pass in the animation, and another argument, child, is the object we need to scale.

ScaleTransition(
    scale: scale,
    child: Container(
        alignment: Alignment.center,
        width: sw,
        height: 70,
        color: Colors.blue.withAlpha(50),
    ),
    ),
),
Copy the code

Finally, we’ll put the ScaleTransition in _buildAnimation as well.

Widget _buildAnimation(BuildContext context, Widget child) { final sw = MediaQuery.of(context).size.width; return Stack( children: [ Utils.buildJuejinSvg(Colors.grey), Positioned( left: 0, top: 0, child: ScaleTransition( scale: scale, child: Container( alignment: Alignment.center, width: sw, height: 70, color: Touri.blue. WithAlpha (50),),),), toy (left: sw / 2-22.5, top: 11.5, child: ClipRect(child: Align (alignment: alignment. TopCenter widthFactor: 1.0, heightFactor: offsetForColorChanges. The value, the child: Utils.buildJuejinSvg(Colors.blue), ), ), ), ], ); }Copy the code

Finally, build the animation through AnimatedBuilder.

  @override
  Widget build(BuildContext context) {
    _playAnimation();

    return AnimatedBuilder(
      animation: controller,
      builder: _buildAnimation,
    );
  }
Copy the code

So that’s the animation. Let’s go over it.

  1. Start by creating a stateless widget JueJinAnimation;
  2. Define 2 animation objects;
  3. Implement animation method _buildAnimation;
  4. Let AnimatedBuilder wrap the animation method;
  5. Play the animation.

The animation

Perfect, the JueJinAnimation class is created. Next, use the JueJinAnimation class in main.dart.

This state uses the animation class JueJinAnimation. Since the animation inside the Flutter is controlled by the AnimationController, So we need to create an AnimationController and pass it to the JueJinAnimation class:

    _juejinAnimationController = AnimationController(
      duration: const Duration(milliseconds: 1000),
      vsync: this,
    );
Copy the code

All of the above are easy to understand, there is only one vsync, please refer to here. In order to use vsync we need to add a Mixin.

class _PullToRefreshExampleState extends State<_PullToRefreshExample>
    with TickerProviderStateMixin {
    // TODO: code here
    }
Copy the code

Finally, we populate the drop-down refresh builder method to see what widgets need to be returned for each corresponding state.

  Widget _buildRefreshBuilder(
    BuildContext context,
    RefreshIndicatorMode refreshState,
    double pulledExtent,
    double refreshTriggerPullDistance,
    double refreshIndicatorExtent,
  ) {
    switch (refreshState) {
      case RefreshIndicatorMode.inactive:
      case RefreshIndicatorMode.drag:
      case RefreshIndicatorMode.done:
        return Utils.buildJuejinSvg(Colors.grey);
        break;
      case RefreshIndicatorMode.armed:
        return Utils.buildJuejinSvg(Colors.blue);

        break;
      case RefreshIndicatorMode.refresh:
        return JueJinAnimation(
          animationController: _juejinAnimationController,
          controller: _juejinAnimationController?.view,
        );

        break;
      default:
        return Utils.buildJuejinSvg(Colors.grey);
        break;
    }
  }
Copy the code

conclusion

Flutter implements some simple dynamic effects that are easy to understand and learn. The basic dynamic effects of Flutter are implemented through built-in classes such as Tween, Animation, AnimationController, AnimatedBuilder, and so on. Source code supplied.