Widgets trong Flutter
1. tại sao học widget đầu tiên
Gắn với khái niệm code ra được cái app hello world thì bạn cần biết widget là gì để có thể tạo ra các widget. Vì trong flutter, khái niệm widget là khái niệm xuyên suốt trong quá trình code với flutter.
nếu bạn nào đã từng tiếp xúc với react, vue, … nói chung là các frameword khuynh hướng hiện đại sẽ mang tư tưởng của component. và flutter cũng thế, Flutter widgets cũng giống 1 component trong reactjs. Flutter widgets mục đích là biểu thị UI, render UI cho người dùng thấy. Flutter có cơ chế state, khi state thay đổi thì widget của flutter sẽ được render lại.
2. Chỉnh sửa lại code của project fluter cho dễ đọc.
chũng ta nên viết lại 1 cách ngắn gọn như này :
bạn copy dán vào file main.dart để xem code thực hiện của flutter sẽ có kết quả như này:
Tổng quanvề Widget
Không giống code native như ở Android hoặc IOS, Flutter có một cơ chế build, update UI hoàn toàn khác biệt. Và cơ chế đó như sau :

khi trạng thái ( state ) thay đổi thì UI sẽ được render lại ( function Widget build(BuildContext context) { sẽ được gọi lại.
Tức là với ví dụ trên, thì đầu game flutter chạy hàm main.dart, vào đây thấy cái hàm void main thì chạy trước, hàm voi main thì cho chạy cái hàm runApp, mà cụ thể cái runApp, vì nó là thư viện flutter cung cấp.
Trong hàm runApp nó chạy cái widget MyApp do chính chúng ta định nghĩa. Mình thích định nghĩa cái gì cũng được. tạm thời chúng ta sẽ thấy là MyApp sẽ extend từ cái StatelessWidget ngoài ra chúng ta còn có 1 loại khác để có thể kế thừa là StatefulWidget
- StatelessWidget là không có state ( không thay đổi nội bộ UI )
- StatefullWidget là có state ( có sự thay đổi quản lý state và sự thay đổi UI theo state)
Trong flutter họ có định nghĩa sẵn cho chúng ta vài cái widget để sài cho tiện
trong ví dụ là MaterialApp là widget kế thừa các kiến trúc theo chuẩn design marterial, Scaffold là widget bao chứa toàn bộ code chúng ta vào trong nó ( phủ đầy giao diện chúng ta).
=> Bạn nào code HTML rồi thì cứ tưởng tượng cái thẻ marterial giống như là thẻ html có thẻ head rồi nhúng css của marterial vào, còn thẻ scaffold là như thẻ body của html vậy thôi.
Trong 1 thẻ widget thì sẽ có các Thộc tính đi kèm, có thể các thuộc tính đi kèm lại truyền thêm các widget, giống như bạn xây dùng 1 thẻ Widget cho riêng bạn, tuy kế thừa từ widget nhưng cũng có thể có các thuộc tính đi kèm là đối tượng widget được truyền vào.
ví dụ trên là thẻ MaterialApp có thuộc tính title truyền vào là 1 text, và thuộc tính theme truyền vào là 1 ThemeData. Nhưng còn thẻ Scaffold thì co thuộc tính body truyền vào 1 widget Center
Widget thì được chia ra làm 2 loại. Đó là StatelessWidget và StatefulWidget. Hiện tại chúng ta cũng thấy có 2 cái widget Text và Center trong ví dụ trên, vậy câu hỏi mình tự đặt ra khi mới học flutter đó là 2 cái widget đó là dạng nào trong 2 loại widget của flutter ? Vậy câu trả lời là nếu bạn view define nó ra sẽ thấy nó extend từ đứa nào là biết chứ cần gì search chi phức tạp

Bài này dài rồi, mình xin tóm gọn là chỉ bằng 2 câu nói:
1. Để xây dựng các thành phần UI trong fluttter chúng ta dùng các widget ( widget thì giống khái niệm component trong các kiến trúc web )
2. chúng ta có 2 loại widget làStatelessWidgetvàStatefulWidget
1) Stateless widgets
Có nghĩa là StatelessWidget chỉ đơn thuần nhận dữ liệu và hiển thị 1 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 phải render lại. Nếu phải render lại thì là do tác động từ bên ngoài vào.
Vậy nên, nó không có liên quan gì đến State cả. Bản thân nó cũng không có hàm
createState mà thay vào đó là hàm build(BuildContext)
Ví dụ: ta có thể nhìn 1 vài mẫu Stateless widgets.
Xét loại Text widget là để khởi tạo trong một constructor và những properties thường để build widget và hiển thị lên màn hình
2) Stateful widgets
Để hiểu rõ hơn ta xét ví dụ như sau:
Khi xoay màn hình thì coi như ứng dụng sẽ dựng lại các Widget và sẽ render lại Widget từ những dữ liệu ban đầu. Trong Android SDK để khôi phục lại trạng thái cho các TextView, RadioButton, CheckBox, ... bạn sẽ phải thao tác với
savedInstanceState. Với Flutter thì nó làm sẵn với tên State này, nó sẽ tận dụng lại State cũ, lấy tất cả giá trị trong đó ra để render lại Widget.Và ví dụ cho StatefulWidget sẽ là như sau:

II. Demo
Để nhanh hiểu ta cứ làm ví dụ cho nhanh Trong bài này ta sẽ thử với 3 action sau:
- Làm thế nào để chuyền app state cho widget
- Làm sao để rebuild widget sau khi cập nhật state
- Làm sao có thể điều hướng màn hình và vẫn đồng bộ được state.
Cụ thể sẽ là:
- Tăng biến đếm trong MyHomePage
- Chuyển sang màn hình MySecondPage
- Giảm biến đếm trong MySecondPage
Hiện tại bạn chỉ nên quan tâm file code trong lib folder thôi nhé

main.dart như sau:import 'package:flutter/material.dart';
import 'MyHomePage.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
State<StatefulWidget> createState() {
// TODO: implement createState
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
int counter;
void initState() {
// TODO: implement initState
super.initState();
counter = counter ?? 0;
}
void _decrementCounter(_){
setState(() {
counter--;
print('decrement: $counter');
});
}
void _incrementCounter(_){
setState(() {
counter++;
print('increment: $counter');
});
}
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(
title: 'My Home Page',
counter: counter,
decrementCounter: _decrementCounter,
incrementCounter: _incrementCounter,
),
);
}
}
Trong MyHomePage.dart
import 'package:flutter/material.dart';
import 'MySecondPage.dart';
class MyHomePage extends StatefulWidget {
MyHomePage(
{Key key,
this.title,
this.counter,
this.decrementCounter,
this.incrementCounter})
: super(key: key);
final String title;
final int counter;
final ValueChanged<void> decrementCounter;
final ValueChanged<void> incrementCounter;
State<StatefulWidget> createState() {
// TODO: implement createState
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage> {
void _onPressed() {
widget.incrementCounter(null);
}
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
Text(
widget.counter.toString(),
style: Theme.of(context).textTheme.display1,
),
RaisedButton(
child: Text('next screen'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MySecondPage(
widget.decrementCounter,
title: 'My Second Page',
counter: widget.counter,
)));
},
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _onPressed,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
Và cuối cùng MySecondPage.dart
import 'package:flutter/material.dart';
class MySecondPage extends StatefulWidget {
MySecondPage(
this.decrementCounter, {
Key key,
this.title,
this.counter,
}) : super(key: key);
final String title;
final int counter;
final ValueChanged<void> decrementCounter;
State<StatefulWidget> createState() {
// TODO: implement createState
return _MySecondPageState();
}
}
class _MySecondPageState extends State<MySecondPage> {
void _onPressed() {
widget.decrementCounter(null);
}
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
Text(
super.widget.counter.toString(),
style: Theme.of(context).textTheme.display1,
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _onPressed,
tooltip: 'Decrement',
child: Icon(Icons.indeterminate_check_box),
backgroundColor: Colors.red,
),
);
}
}

0 Nhận xét