Tìm hiểu AnimatedContainer Widget qua ví dụ cơ bản

Nếu bạn chưa xem video “Widget of the Week” về  AnimatedContainer Widget, hãy xem video đó trước.

Bài viết này sẽ sử dụng các khái niệm được nói đến trong video và biến chúng thành code mà bạn có thể tự xử lý. Cách học nhanh nhất là vừa học vừa làm. Vì vậy, hãy mở IDE yêu thích của mình hoặc sử dụng DartPad và bắt đầu “hacking” nhé. Bạn còn chờ gì nữa mà không bắt đầu ngay bây giờ?

1. Thiết lập:

Code cho hướng dẫn này nằm trên DartPad, vì vậy hãy nhấp vào liên kết đó để bắt đầu.

Nếu bạn thích sử dụng Android Studio hoặc VS Code, hãy bắt đầu dự án Flutter mới và thay thế main.dart bằng đoạn code sau:

Dart

import 'package:flutter/material.dart';

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

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

class AnimatedContainerDemo extends StatefulWidget {
  @override
  _AnimatedContainerDemoState createState() => _AnimatedContainerDemoState();
}

class _AnimatedContainerDemoState extends State<AnimatedContainerDemo> {

  // state variables                           <-- state
  final _myDuration = Duration(seconds: 1);
  var _myValue = Color(0xFF00BB00);
  final _myNewValue = Color(0xFF0000FF);

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Center(
          child:

          // Update this code                  <-- AnimatedContainer
          AnimatedContainer(
            color: _myValue,
            duration: _myDuration,
            child: SomeOtherWidget(),
          ),
        ),
        updateStateButton()
      ],
    );
  }

  Align updateStateButton() {
    return Align(
      alignment: Alignment.bottomCenter,
      child: Padding(
        padding: EdgeInsets.only(bottom: 100),
        child: RaisedButton(
          child: Text('Update State'),
          onPressed: () {
            setState(() { //                    <-- update state
              _myValue = _myNewValue;
            });
          },
        ),
      ),
    );
  }
}

class SomeOtherWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 200,
      height: 200,
    );
  }
}

Những điều cần lưu ý:

2. Màu sắc

Bạn có thể tạo animation để chuyển đổi background cho Widget bất kỳ giữa hai màu khác nhau.

Dart

// start with green
var _myValue = Color(0xFF00BB00);
// end with blue
final _myNewValue = Color(0xFF0000FF);

AnimatedContainer trông như thế này:

Dart

AnimatedContainer(
  color: _myValue,
  duration: _myDuration,
  child: SomeOtherWidget(),
),

Trong đó _myDurationDuration được set một giây.

Nếu bạn chạy ứng dụng và nhấn nút Update State ngay bây giờ, bạn sẽ thấy màu sắc thay đổi:

Ghi chú:

Nếu bạn làm việc trong Android Studio hoặc VS Code, hãy nhớ thực hiện Hot Restart thay vì Hot Reload để đặt lại (reset) state giữa mỗi ví dụ dưới đây.

3. Border

Bạn có thể tạo animation cho chiều rộng (width) của border.

Dart

// starting width
var _myValue = 0.0;
// ending width
final _myNewValue = 7.0;

AnimatedContainer trông như thế này:

Dart

AnimatedContainer(
  duration: _myDuration,
  decoration: BoxDecoration(
    color: Color(0xFF0099EE),
    border: Border.all(
      color: Color(0xFF12569A),
      width: _myValue,
    ),
  ),
  child: SomeOtherWidget(),
),

Nhấn nút Update State và xem sự thay đổi chiều rộng border :

3. Border Radius

Bạn có thể tạo animation để thay đổi giá trị borderRadius của 1 Widget bất kỳ.

Dart

// starting radius
var _myValue = 0.0;

// ending radius
final _myNewValue = 40.0;

AnimatedContainer trông như thế này:

Dart

AnimatedContainer(
  duration: _myDuration,
  decoration: BoxDecoration(
    color: Color(0xFF0099EE),
    borderRadius: BorderRadius.circular(_myValue),
    border: Border.all(
      color: Color(0xFF12569A),
      width: 7.0,
    ),
  ),
  child: SomeOtherWidget(),
),

Xem thử điều gì sẽ xảy ra khi bạn nhấn nút.

4. Background Image

Được rồi, tôi không thể tìm ra cách tạo hoạt ảnh cho hình ảnh, nhưng nếu bạn muốn thay đổi hình nền (background image), bạn có thể làm như sau:

Dart

AnimatedContainer(
  duration: _myDuration,
  decoration: BoxDecoration(
    image: DecorationImage(
      image: NetworkImage('https://placebear.com/300/300'),
    ),
    borderRadius: BorderRadius.circular(40),
  ),
  child: SomeOtherWidget(),
),
Làm gì để tạo hoạt ảnh?

5. Shadow

Có một số thứ có thể tạo hiệu ứng đổ bóng: màu sắc, offset, bán kính mờ (blur radius) và bán kính lan rộng (spread radius). Bán kính mờ càng lớn thì càng mờ. Bán kính lan rộng càng lớn thì bóng đổ càng lớn.

Hãy tạo hiệu ứng cho offset, bán kính mờ và bán kính lan rộng cùng một lúc.

Dart

// starting
var _myValue = 0.0;

// ending
final _myNewValue = 40.0;

AnimatedContainer trông như thế này:

Dart

AnimatedContainer(
  duration: _myDuration,
  decoration: BoxDecoration(
    color: Color(0xFF0099EE),
    boxShadow: [
      BoxShadow(
        color: Colors.black,
        offset: Offset(_myValue, _myValue),
        blurRadius: _myValue,
        spreadRadius: _myValue,
      )
    ],
  ),
  child: SomeOtherWidget(),
),

Nhấp vào nút Update Statei và xem độ bóng lớn dần.

6. Gradient

Bạn có thể tạo hoạt ảnh để thay đổi màu sắc gradient.

Dart

// starting
var _myValue = Colors.green;

// ending
final _myNewValue = Colors.blue;

Vì ví dụ chỉ có một biến giá trị, tôi đã thực hiện thủ thuật nhỏ phía bên phải của gradient để có thêm hoạt ảnh màu.

Dart

AnimatedContainer(
  duration: _myDuration,
  decoration: BoxDecoration(
    gradient: LinearGradient(
      colors: [
        _myValue,
        Colors.black.withBlue(_myValue.blue),
      ]
    ),
  ),
  child: SomeOtherWidget(),
),

Nhấn nút để xem các sắc thái thay đổi.

7. Shape

Decoration có thuộc tính shape, nhưng bạn không thể tạo hoạt ảnh cho thuộc tính đó vì BoxShape chỉ có thể là circle hoặc rectangle. Vì vậy, tôi chỉ nói về widthheight hoạt ảnh ở đây.

Dart

// starting
var _myValue = 0.0;

// ending
final _myNewValue = 100.0;

AnimatedContainer trông như thế này:

Dart

AnimatedContainer(
  duration: _myDuration,
  color: Color(0xFF0099EE),
  width: 200 + _myValue,
  height: 200 - _myValue,
  child: SomeOtherWidget(),
),

8. Padding

Tôi phải thay đổi cấu trúc dự án để nhìn thấy sự thay đổi của padding, vì vậy tôi bỏ qua cái này. Dưới đây là đoạn code cơ bản:

Dart

AnimatedContainer(
  duration: _myDuration,
  padding: EdgeInsets.all(_myValue),
  ...
),

9. Alignment

Alignment của (0, 0) cũng giống như căn giữa, alignment của (-1, -1) là phía trên bên trái và (1, 1) là phía dưới bên phải.

Dart

// starting
var _myValue = -1.0;

// ending
final _myNewValue = 1.0;

Đây là AnimatedContainer:

Dart

AnimatedContainer(
  duration: _myDuration,
  alignment: Alignment(_myValue, _myValue),
  color: Color(0xFF0099EE),
  width: 200,
  height: 200,
  child: Text('Flutter'),
),

Và nó như thế này:

10. Transform

Bạn có thể xoay, dịch chuyển và nghiêng. Vấn đề là bạn phải sử dụng thêm Matrix4 để hỗ trợ làm điều đó. Đây là một đoạn code về phần đó.

Dart

// starting
var _myValue = 0.0;
// ending
final _myNewValue = 2.0;

AnimatedContainer:

Dart

AnimatedContainer(
  duration: _myDuration,
  width: 50,
  height: 50,
  transform: Matrix4.skew(_myValue, _myValue),
  color: Color(0xFF0099EE),
  child: SomeOtherWidget(),
),

11. Duration

Chúng ta đang sử dụng duration một giây cho tất cả các ví dụ ở trên, nhưng bạn có thể thay đổi duration đó theo ý của mình.

Quay lại ví dụ về alignment, hãy làm nó chậm lại tí:

Dart

final _myDuration = Duration(days: 356);

12. Animation Curve

Animation curve cho biết tốc độ di chuyển của nó tại các điểm khác nhau trong suốt duration. Có rất nhiều loại để bạn lựa chọn và đây là ví dụ Curves.elasticInOut về alignment (với duration được set thành một số hợp lý hơn):

Dart

AnimatedContainer(
  duration: Duration(seconds: 3),
  curve: Curves.elasticInOut,
  alignment: Alignment(_myValue, _myValue),
  color: Color(0xFF0099EE),
  width: 200,
  height: 200,
  child: Text('Flutter'),
),

Tóm lại

Có nhiều sự kết hợp của những thứ bạn có thể tạo hoạt ảnh trên AnimatedContainer ngay cả khi chúng ta làm việc này liên tục trong Duration(days: 356). Tôi chỉ cho bạn thấy những cái chính với một biến duy nhất. Bạn có thể kết hợp tùy thích với nhau.

Lưu ý nhỏ là trong khi ngẫm nghĩ viết bài này, tôi đã phát hiện ra lỗi trong cách diễn đạt thông báo lỗi Flutter.

Làm thế nào người ta có thể thực hiện các vòng tròn đỏ tự do trên nền đỏ?

BoxDecoration có thuộc tính là color, không phải là backgroundColor. Vì vậy, tôi đã thực hiện tìm kiếm trong kho lưu trữ Flutter cho thông báo lỗi đó, hóa ra là từ một câu lệnh assert. Sau đó, tôi đã chỉnh sửa từ ngữ trong tệp đó và thực hiện một pull request. Ngay sau đó, yêu cầu đã được chấp nhận và merged. Tôi thích Flutter vì nó là open source.

Bài viết được dịch từ đây.

Exit mobile version