Skip to content

[Flutter] 使用 AnimatedContainer 來將元件變形加上動畫

在設計 APP 的過程中,我們經常會有需要將元件變形便上動畫的時候。常見的一個例子,便是展開眾多的選項時,要顯示如卷軸攤開般的動畫。

當然,如果直接改動元件的長寬當然也可以做到,可是加上漸變的動畫總是更好。

本文將記述如何透過 AnimatedContainer 來完成元件變形的漸變動畫。AnimatedContainer 是一個跟 Container 類似的 widget,不過會在我們調整 AnimatedContainer 的屬性時,在舊值與新值間自動建立動畫。


如何使用 AnimatedContainer

我們會需要用到以下元件:

  • StatefulWidget:用來在每次更動元件屬性於更新頁面
  • AnimatedContainer:如上所述,會自動產生漸變動畫的元件
  • FloatingActionButton:控制元件變形的按鈕

另外,AnimatedContainer 更動的屬性值就以 Random 的方式產生,分別更改以下各類屬性值:

  • height: 元件的高度
  • width:元件的寬度
  • decoration-borderRadius:元件的邊角弧度(border radius)
  • decoration-color:元件的顏色
  • duration:動畫的時長

那麼,以下直接看段範例程式碼:

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


// Main
void main() => runApp(MyApp());


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: AnimatedContainerPage(),
    );
  }
}


class AnimatedContainerPage extends StatefulWidget {
  @override
  _AnimatedContainerPage createState() => _AnimatedContainerPage();
}


class _AnimatedContainerPage extends State<AnimatedContainerPage> {
  // Init
  int _duration = 1000;
  double _width = 100.0;
  double _height = 100.0;
  Color _color = Colors.red;
  BorderRadiusGeometry _borderRadius = BorderRadius.circular(0);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("AnimatedContainer test"),
        ),

        // AnimatedContainer component
        body: Center(
          child: AnimatedContainer(
            width: _width,
            height: _height,
            decoration: BoxDecoration(
              color: _color,
              borderRadius: _borderRadius,
            ),
            duration: Duration(milliseconds: _duration),
            curve: Curves.fastOutSlowIn,
          ),
        ),

        // Button
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.replay_circle_filled),
          backgroundColor: _color,
          onPressed: () {

            // Rebuild the widget
            setState(() {
              _duration = 500 + Random().nextInt(500);
              _width = Random().nextInt(200).toDouble();
              _height = Random().nextInt(200).toDouble();
              _color = Color.fromRGBO(
                Random().nextInt(256),
                Random().nextInt(256),
                Random().nextInt(256),
                1,
              );
              _borderRadius = BorderRadius.circular(Random().nextInt(100).toDouble());
            });
          },
        ),
      )
    );
  }
}


Output:


References


Read More

Tags:

Leave a Reply