Khi mới làm việc với Flutter và được tiếp xúc với cả Listview và Column kết hợp với SingleChildScrollView rất nhiều người sẽ bị nhầm lẫn giữa việc sử dụng các widgets trên. Đơn giản bởi vì là dường như chúng cùng làm một chức năng nó là hiển thị các thành phần giao diện dưới dạng một danh sách có thể cuộn được.
Chúng ta sẽ cùng tìm hiểu về Listview so với Column kết hợp SingleChildScrollView để thấy được sự khác biệt của chúng.
Giả sử ta có một danh sách các item như sau:

Chúng ta sẽ lần lượt thử ListView sau đó là Column kết hợp với SingleChildScrollView để kết luận trường hợp nào sử dụng cái nào là tốt hơn.
ListView
ListView là một Widget hiển thị không giới hạn số lượng các phần tử con bên trong nó. ListView sẽ gồm ListView() và ListView.Builder().
Khi nào ta sẽ sử dụng ListView:
- Khi cần thị thị một widget mà widget này được xuất hiện lặp đi lặp lại nhiều lần.
- Khi chỉ cần xử lý hiện thị cho các widget mà chúng đang được hiển thị trên màn hình của thiết bị.
Lưu ý khi ta sử dụng ListView() và ListView.Builder()
- ListView() xử lý hiển thị tất các phần tử trong danh sách, ngay cả khi các phần tử này không được hiển thị trên màn hình thiết bị.
- ListView.Builder() chỉ xử lý hiện thị các phần tử mà được hiện thị trên màn hình thiết bị.
Ví dụ ListView()
class ListViewWithoutBuilderScreen extends StatelessWidget { const ListViewWithoutBuilderScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( body: Container( padding: EdgeInsets.only(top: 10), child: ListView( children: [ ItemWidget(), ItemWidget(), ItemWidget(), ItemWidget() ], ), ), ); } }
Ví dụ ListView.Builder()
class ListViewScreen extends StatefulWidget { const ListViewScreen({Key? key}) : super(key: key); @override State<ListViewScreen> createState() => _ListViewScreenState(); } class _ListViewScreenState extends State<ListViewScreen> { @override Widget build(BuildContext context) { return Scaffold( body: Container( padding: EdgeInsets.only(top: 10), child: ListView.builder( itemCount: 100000, itemBuilder: (BuildContext buildContext, int index) { return ItemWidget(); }, )), ); } }
Kết quả thu được sẽ là:

SingleChildScrollView + Column
Ta thường sử dụng Column khi muốn hiển thị các widget được sắp xếp theo chiều dọc, và SingleChildScrollView cho phép chúng ta có thể cuộn (scroll) được các thành phần trong Column.
Khi sử dụng SingleChildScrollView kết hợp với Column thì toàn bộ các item bên trong nó sẽ được xử lý để hiện thị (render), dù cho chỉ có một vài item hiện tại đang xuất hiện trên màn hình thiết bị.
Từ lưu ý trên ta có thể dễ dàng thấy được vấn đề ở đây là khi ta sử dụng SingleChildScrollView + Column mà các phần tử bên trong nó số lượng không nhiều thì ta hoàn toàn có thể xử dụng sự kết hợp này.
Khi nào ta sử dụng SingleChildScrollView + Column
- Khi các phần tử con là các phần tử khác nhau và cần cuộn (scroll) được giao diện.
- Khi các phần tử có giao diện phức tạp và số lượng phần tử không nhiều.
Ví dụ:
class ScrollViewScreen extends StatefulWidget { const ScrollViewScreen({Key? key}) : super(key: key); @override State<ScrollViewScreen> createState() => _ScrollViewScreenState(); } class _ScrollViewScreenState extends State<ScrollViewScreen> { List<int> dataList = new List<int>.generate(100000, (index) => index + 1); @override Widget build(BuildContext context) { return Scaffold( body: Container( padding: EdgeInsets.only(top: 20), child: SingleChildScrollView( child: Column( children: dataList.map((e) => ItemWidget()).toList(), ), ), ), ); } }
Kết quả là:

Vì là sử dụng SingleChildScrollView + Column cùng với số lượng phần tử lớn nên màn hình của chúng ta sẽ có giấu hiệu bị giật lag.
Chi tiết source code mọi người tham khảo tại đây.
Leave a Reply