Trang chủ Kiến Thức Công Nghệ Tìm hiểu AnimatedContainer Widget qua ví dụ cơ bản
Công Nghệ

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

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

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 ý:

  • Các biến state được sử dụng ở trong ví dụ này được khai báo ở phía trên cùng của class State. Bạn có thể khởi tạo giá trị ban đầu và giá trị cuối cùng ở đây. Trong ví dụ đầu tiên, bạn sẽ tạo animation cho màu sắc.
  • Hãy tìm widget AnimatedContainer ở phần giữa của đoạn code. Chúng ta sẽ cùng nhau tìm hiểu các thuộc tính khác trong bài viết này.
  • Ở phần dưới, bạn sẽ tìm thấy phương thức setState(). Bạn sẽ không cần thay đổi  bất kỳ điều gì vì mọi ví dụ sẽ cập nhật _value với _newValue, nhưng đây là nơi bạn sẽ khiến các Animation bắt đầu animate.

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ú:

  • SomeOtherWidget cần phải trong suốt nếu không bạn sẽ không thấy màu sắc thay đổi trên AnimatedContainer bên dưới nó.

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.

Bài viết cùng chuyên mục
Tối ưu ứng dụng với cấu trúc dữ liệu cơ bản và bitwise
Công Nghệ

Tối ưu ứng dụng với cấu trúc dữ liệu cơ bản và bitwise

Trong bài viết này, 200Lab sẽ chia sẻ những trường hợp dễ...

Công Nghệ

So sánh Flutter vs React Native: Framework nào đáng học năm 2021

Điểm chung của Flutter, React Native đều là Cross-platform Mobile, build native...

HTTP/2 là gì? So sánh HTTP/2 và HTTP/1
Công Nghệ

HTTP/2 là gì? So sánh HTTP/2 và HTTP/1

Từ khi Internet ra đời, sự phát triển về các giao thức...

Upload File từ Frontend đến Backend mà rất nhiều bạn vẫn đang làm sai!!
Công Nghệ

Upload File từ Frontend đến Backend mà rất nhiều bạn vẫn đang làm sai!!

1. Client encode file (base64) rồi gởi về backend 200Lab đã từng...

Công Nghệ

React Native – Hướng dẫn làm việc với Polyline và Animated-Polyline trên Map

Vẽ đường đi trên bản đồ là một nghiệp vụ vô cùng...

Công Nghệ

Hybrid App và Native App: Những khác biệt to lớn

Bất cứ khi nào một công ty quyết định làm ứng dụng...

Web/System Architecture 101 – Kiến trúc web/hệ thống cơ bản cho người mới
Công Nghệ

Web/System Architecture 101 – Kiến trúc web/hệ thống cơ bản cho người mới

Đây là một kiến trúc cơ bản mà bất kì một người...

Công Nghệ

Tư duy kiến trúc thông qua các trò chơi mà rất nhiều bạn không biết

Tư duy kiến trúc là gì? Tư duy kiến trúc có thể...