Flutter is on the rise. Yesterday, Google officially released Flutter1.7, which includes Android X support, some updates to the Play Store, some new and enhanced components, and some bug fixes.

In this article we will work together to develop a stunning list display with scrolling and animated backgrounds. Take a look at the renderings:

Train of thought

As the list scrolls, the vertical scrolling distance is obtained, and this value is converted into units of Angle to drive the gear rolling

Entrance to the file

Flutter projects all start with lib/main.dart:

import 'package:flutter/material.dart';
import 'demo-card.dart';
import 'items.dart';
import 'animated-bg.dart';

void main() => runApp(AnimationDemo());

class AnimationDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: MyHomePage(title: 'List scrolling')); }}class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  ScrollController _controller = new ScrollController();

  List<DemoCard> get _cards =>
      items.map((Item _item) => DemoCard(_item)).toList();

  @override
  Widget build(BuildContext context) {
    returnScaffold( backgroundColor: Colors.black, appBar: AppBar(title: Text(widget.title)), body: Stack( alignment: AlignmentDirectional.topStart, children: <Widget>[ AnimatedBackground(controller: _controller), Center( child: ListView(controller: _controller, children: _cards), ) ], ), ); }}Copy the code

In the main.dart file, there are several imported files:

  • demo-card.dartThe card widget, the list is the widget of the loop
  • items.dartThe data presented by the card is in this file. In this project, we wrote some mock data, and the data of the real production project is more from HTTP request
  • animated-bg.dartBackground gear widget

This file mainly uses some basic Flutter widgets. If you don’t know how to use Flutter widgets, please check the official website. In addition, please pay attention to the list rendering. We’ll say ScrollController _controller = new ScrollController(); To get the vertical scrolling distance

Mock data for the card

Dart: The children of the listView in main.dart are generated from the same six data sets as the children of the listView:

import 'package:flutter/material.dart';

class Item {
  String name;
  MaterialColor color;
  IconData icon;
  Item(this.name, this.color, this.icon);
}

List<Item> items = [
  Item('one', Colors.amber, Icons.adjust),
  Item('. ', Colors.cyan, Icons.airport_shuttle),
  Item('叁', Colors.indigo, Icons.android),
  Item('boss', Colors.green, Icons.beach_access),
  Item('wu', Colors.pink, Icons.attach_file),
  Item('land', Colors.blue, Icons.bug_report)
];

Copy the code

Three fields:

  • Name The name on the left of the card
  • Color Indicates the background color of the card
  • Icon Indicates the icon on the right of the card

Card Widget

Dart: children: items.map((Item _item) => DemoCard(_item)).tolist (); Pass _item to DemoCard, which is the props in React or Vue. The difference is that the parameters to a flutter can be either anonymous or named. Here we use anonymous upload parameters. Take a look at how the card Widget receives parameters:

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

class DemoCard extends StatelessWidget {
  DemoCard(this.item);
  final Item item;

  static final Shadow _shadow =
      Shadow(offset: Offset(2.0.2.0), color: Colors.black26);
  final TextStyle _style = TextStyle(color: Colors.white70, shadows: [_shadow]);

  @override
  Widget build(BuildContext context) {
    return Card(
      elevation: 3,
      shape: RoundedRectangleBorder(
        side: BorderSide(width: 1, color: Colors.black26),
        borderRadius: BorderRadius.circular(32),
      ),
      color: item.color.withOpacity(7.),
      child: Container(
        constraints: BoxConstraints.expand(height: 256),
        child: RawMaterialButton(
          onPressed: () {},
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: <Widget>[
                  Text(item.name, style: _style.copyWith(fontSize: 64)),
                  Icon(item.icon, color: Colors.white70, size: 72() [() [() [() [() [() [() }}Copy the code

React/Vue: StatelessWidget; StatelessWidget: React/Vue: StatelessWidget;

DemoCard(this.item);
final Item item;
Copy the code

Use the Card component to quickly restore a Card style

  • elevationParameter control card suspension height
  • shapeParameter control card fillet
  • colorParameter control card background,item.color.withOpacity(.7)Make the background transparent by 30%

Then you use columns and rows to control the presentation of the layout

Background gear rotation

Take a look at the source code of the background component and explain one by one:

import 'package:flutter/material.dart';

class AnimatedBackground extends StatefulWidget {
  AnimatedBackground({Key key, this.controller}) : super(key: key);

  final ScrollController controller;

  @override
  _AnimatedBackgroundState createState() => _AnimatedBackgroundState();
}

class _AnimatedBackgroundState extends State<AnimatedBackground> {
  get offset => widget.controller.hasClients ? widget.controller.offset : 0;

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: widget.controller,
      builder: (BuildContext context, Widget child) {
        return OverflowBox(
          maxWidth: double.infinity,
          alignment: Alignment(4.3),
          child: Transform.rotate(
            angle: offset / - 512.,
            child: Icon(Icons.settings, size: 512, color: Colors.white), ), ); }); }}Copy the code

Dart. This controller is the ListView controller. We use widget.controller.offset to get the vertical scrolling distance. We need to constantly refresh the rotation Angle of the gear as the list scrolls, so we use the AnimatedBuilder component, which has two important parameters:

  • The animation passes widget.controller to the animation
  • Each time the Builder animation changes, the rendering is re-executed, which achieves the linkage effect

The OverflowBox component provides excellent control over the display position of the child components with alignment(anchor points). Here we used alignment(4, 3) to position the gears to the lower left of the screen. It’s the transform. rotate component that makes the gears work. Here we have an arc length formula: L=α (radians) × r(radius), so we use Angle: offset / -512

  • Why 512, because of our gearsize: 512
  • Why does it have a minus sign, so that we can have the gear rotate counterclockwise when we scroll up the list, and clockwise when we scroll down the list

Use the Widget

Space is limited, we can not explain the components used one by one, if you have questions, please go to the official website to check the usage

  • MaterialApp
  • Scaffold
  • AppBar
  • Stack
  • Center
  • ListView
  • Card
  • RawMaterialButton
  • Column
  • Row
  • AnimatedBuilder
  • OverflowBox
  • Transform
  • Icon

A link to the

This article can learn because a lot of knowledge, including: StatelessWidget/StatefulWidget create, create and use the local data, the list of display and control, vertical, horizontal layout, etc., want to see the effect of students can be directly run the source code

  • The source address
  • Blog Post
  • Nuggets this article address