Hỏi - đáp Nơi cung cấp thông tin nghề nghiệp và giải đáp những thắc mắc thường gặp của bạn

Flutter rules the World: Widget, Stateful Widget and Stateless Widget!

Flinters và Flutter cùng bắt đầu bằng “F”, đọc cũng gần giống nhau, đó không phải là sự ngẫu nhiên, Flutter chắc hẳn là tương lai của Flinters VN !!
– Một bạn Dev tên H của team H công ty F chia sẻ
     Trong thế giới Front-end nói chung, cũng như mảng mobile nói riêng, trong những năm vừa qua, Flutter là một từ khoá rất rất hot. Với  ưu thế  nhạc nào cũng nhảy được, từ mobile, web, tới desktop apps tới embed Flutter đang ngày càng khẳng định được vị thế của mình cùng với cộng đồng ngày càng lớn mạnh, ngày càng được sử dụng rộng rãi.
    Ngoài mấy vụ gần đây anh em cộng đồng dev đau đầu vì lỡ tay upgrade từ bản v1.xx sang v2.xx  mới release xong, cuối cùng nó không chạy được, phải nháo nhào vái lạy khắp nơi tìm cách hạ, hay mấy vụ đồn thổi lương Flutter dev cao ngất ngưởng phải thêm hẳn phụ lục bổ sung cho 300 bài code thiếu nhi ra thì khen Flutter đến ngày mai cũng không hết được.
    Trên blog công ty, bài viết về Flutter của DungTT hay bài review về Flutter của anh ChuanHd trên #septech_geek đã nêu tổng quan về Flutter, những feature của nó rồi nên bài viết này mình xin được vào chủ đề khá là hay ho của Flutter: Widget, một thành phần cốt lõi của Flutter. Nào ta cùng bắt đầu!

Everything is a widget!

Source: Sưu tầm

Widget are foundation of Flutter apps. A widget is a description of part of a user interface
  • Gần như tất cả mọi thứ ở trong một Flutter app đều là Widget, từ những thứ đơn giản nhất như Text, Button tới Screen Layout.. Những widget này được sắp xếp theo thứ tự cấp bậc Parent-Child, những widget này được sắp xếp với nhau và tạo thành một app hoàn chỉnh khi hiển thị.
  • Widget chứa những widget khác bên trong gọi là Container Widget, và hầu hết các widget đều là Container Widget ngoại trừ những widget làm những việc quá cơ bản như “Text widget”.
  • Flutter có một tổ hợp in-built widget phong phú như text, buttons, slider, lists, layouts, gesture detector, animation, v.v.. Bên cạnh đó Flutter team cũng liên tục cải biến, thêm những widget mới để có thể hỗ trợ cho người sử dụng bất kể lúc nào họ cần thông qua các bản cập nhật mới.
  • Chúng ta có thể tự custom widget của riêng mình, sử dụng widget từ nhiều package khác nhau hoặc chỉ dùng những widget đã được xây dựng sẵn. Hệ sinh thái của Flutter cũng cho phép cộng đồng người sử dụng mở rộng với những libraries và widgets của họ.

Chúng ta cùng nhìn qua một app cơ bản được build bằng Flutter:

<Source udacity>
Mọi thứ từ Text, Image, Icon.. đều là widget, bên cạnh đó những thành phần khác của Flutter UI cũng là widget, từ Themes, animation, layout…, ngay cả những event khi chúng ta tap, long-click, scroll,… cũng được biểu thị dưới dạng widget. Thậm chí đến cả chính bản thân app đó cũng chính là một widget.
<Source udacity>

Widget Categories.

<Source udacity>
Dù đa dạng về thể loại, nhưng Flutter chia widget làm 2 loại chính.
  • Stateless widgets
  • Stateful widgets
Trong Flutter, tất cả các widget đều kế thừa từ hai loại trên. Trước khi đi vào cụ thể về từng loại, ta thấy rằng, chúng phân biệt nhau bằng thông qua từ khoá state, vậy state là gì?
Theo Flutter, State là những thông tin có thể được đọc một cách đồng bộ khi Widget được xây dựng và có thể thay đổi trong suốt vòng đời của Widget. Đối tượng State được tạo ra bởi Flutter framework. Để thay đổi Widget, cần cập phải nhật trạng thái (state) của đối tượng bằng hàm setState(), hàm này nằm trong các Stateful Widget. Hàm setState() cài đặt thuộc tính của đối tượng State và cập UI của app.

Stateless widget:

Stateless widget là immutable, có nghĩa là tất cả các fields của nó đều không thay đổi kể từ khi chúng ta rend đến khi destroy chúng.
Stateles Widget không mang trạng thái, nó chỉ thay đổi khi nó được khởi tạo lại. Chúng chỉ đơn thuần nhận dữ liệu và hiển thị một cách thụ động, việc tương tác với nó không sinh ra bất kỳ một event nào để  chính bản thân nó phải render lại.
Một Stateless Widget cơ bản có thể có cấu trúc như sau:
Sau khi khởi tạo, những thuộc tính height, width, color sẽ không bị thay đổi.
Các Icon, IconButton, TextWidget là những ví dụ điển hình về stateless widget.
Life cycle
Bởi vì không có state nên Life cycle của Stateless Widget cũng rất đơn giản, chúng được vẽ, khởi tạo một lần từ khi compile/build.

Stateful widget:

Ngược với stateless widget, stateful widget là những widget có State. State ở đây không chỉ mang trạng thái của một biến, nó mang trạng thái của cả Widget.
Một stateful widget sẽ track những sự thay đổi của state và update UI dựa trên những thay đổi đó.
Hơi mơ hồ phải không, chúng ta có thể hình dung theo cách như thế này:  Nếu ta kéo một ảnh trong slide, bức ảnh di chuyển , nó thay đổi bố cục, thì đó là một stateful states. Một button, khi chúng ta click vào, giao diện hiện ra một form mới, vậy đó là một stateful widget..
Những stateful widget cơ bản có thể kể đến như Image, Form, Checkbox..
Life cycle

Sau khi được khởi tạo lần đầu tiên, statefull widget có vòng đời như được tóm gọn như sau

 Ảnh nguồn thuộc về Jelena Jovanoski chia sẻ trên blog cá nhân
Chi tiết về các step này mình xin trình bày vào các bài viết sau, hoặc mọi người có thể tham khảo tại đây

Để dễ hình dung hơn về các loại Widget thì chúng ta cùng vào một ví dụ cụ thể nhé:

    Thông thường một app sẽ bắt đầu từ một StatelessWidget, nó cũng hiển thị thêm Stateless Widget MyHomePage, với các thuộc tính Text, color, style đều immutable.. đều chỉ khởi tạo thông qua method build đã được override để render graphic UI hiển thị lên màn hình cho người dùng

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Widget',
      theme: ThemeData(
        primarySwatch: Colors.grey,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),

      home: MyHomePage(title: 'Widget Demo'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String title;

  MyHomePage({Key key, this.title}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
        title: Text(this.title),
    ),
    body: Center(
    child: Text('My home page app',
        style: Theme.of(context).textTheme.headline4)
    )
    );
  }
}
   Stateless Widget trong trường hợp này chỉ đơn thuần là hiển thị nội dung, chúng ta không thể thao tác hay thay đổi các thuộc tính gì của chúng.

   Bây giờ chúng ta sẽ sửa lại một chút ở class MyHomePage, thay vì extends từ StatelessWidget, chúng ta chuyển sang extends StatefulWidget

class MyHomePage extends StatefulWidget {

  // Init construction
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;
  // This create state function will be called immediately when app instructed to build a stateful widget
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter;
  
  // Initializing default values of current state which can be used later under build context,
  @override
  void initState() {
    super.initState();
    _counter = _counter ?? 0;
  }

  // Change status _counter
  void _incrementCounter() {
    setState(() {
      _counter++;
      print('Increase state _counter to: $_counter');
    });
  }

  @override
  Widget build(BuildContext context) {
    print('Build widget with new state : $_counter')
    // These widgets such as Scaffold, Appbar, Center, Text ... you guys can read more in Flutter Documentation (https://flutter.dev/docs/reference/widgets)
    // If you are curious about Dart syntax, you can contact Chuan_hd, he is always glad to help you guy
    // I need to sleep now ~.~
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      //Draw center layout 
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Push the button to increase the number:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      //Draw Add button with _incrementCounter() function
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'When click here, the number will be increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Kết quả của chúng ta như sau:

Khi click vào button + , function _incrementCounter() sẽ được gọi và gọi vào hàm setState() bên trong, nó sẽ thay đổi state _counter ( tăng giá trị của _counter)  và gọi lại hàm build cùng với state mới.
Bật debug mode lên ta có thể thấy như sau.
   Qua đó ta có thể thấy rằng app được build dựa trên nhiều Widget lồng vào nhau, các widget khác loại nhau vẫn có thể làm việc, lồng vào nhau. Các Stateless Widget được dùng để hiển thị đơn thuần và không liên quan đến State.

   Mình xin được dừng bài viết hôm nay ở đây, ở phần sau chúng ta sẽ đi chi tiết hơn về Life Cycle của Stateful Widget cũng như State Management trong Flutter và xây dựng một ứng dụng cơ bảng bằng Flutter nhé.

Đối với thành viên của Flinters, những ai quan tâm hay hứng thú với mobile hay Flutter có thể liên hệ với team #flutter_rules_the_world để chúng ta cùng nhau học hỏi, trau dồi và phát triển hơn nữa nhé.

Nguồn: flinters.vn