ด้วยสํานึกในพระมหากรุณาธิคุณสมเด็จพระนางเจ้าสิริกิติ์เป็นล้นพ้นอันหาที่สุดมิได้
ด้วยสํานึกในพระมหากรุณาธิคุณสมเด็จพระนางเจ้าสิริกิติ์เป็นล้นพ้นอันหาที่สุดมิได้


แนวทางจัดการ Layout แสดงรายการสินค้าแบบต่างๆใน Flutter

เขียนเมื่อ 1 ปีก่อน โดย Ninenik Narkdee
masonrygridview gridview listview layout product

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ masonrygridview gridview listview layout product

ปัจจุบัน นักพัฒนาสามารถ ใช้ ChatGPT | Gemini | Claude | Perplexity | Deepseek ช่วยในการแก้ไขปัญหาต่างๆ ในการเขียนโปรแกรม หรือหาข้อมูลเพิ่มเติมได้ง่ายและสะดวก แนะนำให้ทุกคนใช้งานเพื่อพัฒนาศักยภาพของตัวเอง

ดูแล้ว 1,724 ครั้ง


เนื้อหาตอนต่อไปนี้ จะนำตัาอย่างแนวทางการจัดรูปแบบการแสดง
รายการสินค้าในแบบต่างๆ ให้สามารถนำไปใช้งานหรือประยุกต์ต่อได้
จะเป็นเนื้อหาที่ต่อยอดจากบทความ ตามลิ้งค์ด้านล่าง
 
การ Cache ข้อมูลเพิ่มความเร็วสำหรับการโหลดข้อมูล Server http://niik.in/1106
 
เนื้อหานี้จะโค้ดตัวอย่างในตอนท้ายบทความสามารถดาวน์โหลดไปดูเป็นทางได้
โดยในโค้ดตัวอย่างจะมีการใช้งาน package ต่างๆ ที่เกี่ยวข้อง รวมถึงตัวอย่างการนำ Riverpod
มาใช้งานร่วมกับ Provider ในโปรเจ็คเดียวกัน ซึ่งเป็นตัวอย่างกรณีที่เราอาจจะต้องใช้งานร่วมกัน
แต่จริงๆ แล้วควรเลือกอย่างใดอย่างหนึ่ง
 

ในการจัดรูปแบบ layout ตัวอย่างนี้ จะมีด้วยกัน 4 รูปแบบ ดังนี้คือ

    - แบบ ListView ใช้ ListTile จัดรูปแบบ
    - แบบ ListView ไม่ใช้ ListTile จัดรูปแบบ แต่กำหนดเอง
    - แบบ GridView 
    - ใช้ MasonryGridView ที่สามารถกำหนดให้ความสูงแต่ละ Grid แตกต่างกันได้
 

ตัวอย่างผลลัพธ์แต่ละแบบ

 
 
    ในแบบที่สี่หรือแบบสุดท้าย MasonryGridView เรามีการใช้งาน package ที่ชื่อว่า
flutter_staggered_grid_view เข้ามาช่วย ติดตั้งก่อนใช้งานในไฟล์ pubspec.yaml
 
flutter_staggered_grid_view: ^0.7.0
 
    ในตัวอย่างแต่ละหัวข้อ จะนำเฉพาะส่วนของโค้ดที่กำหนดรูปแบบเท่านั้น มาให้ดูเป็นตัวอย่าง
โดยโค้ดสุดท้าย จะเป็นไฟล์รวม product.dart ที่รวมทั้งหมด และมีการคอมเม้นท์ปิดแต่ละรูปแบบ
ไว้และเปิดไว้อันเดียว  ไฟล์ท้้งหมดมีในโค้ดท้ายบทความให้ด้วยโหลด
 

การจัด Layout ด้วย ListView ใช้ ListTile จัดรูปแบบ

    รูปแบบการแสดงจะเป็นในรูปแบบ ListTile ที่เราคุ้นเคย สามารถปรับแต่งเพิ่มเติมได้ตามต้องการ
 
                               // ใช้งาน ListView
                              child: ListView.separated(
                                // กรณีมีรายการ แสดงปกติ
                                controller:
                                    _scrollController, // กำนหนด controller ที่จะใช้งานร่วม
                                itemCount: items.length,
                                itemBuilder: (context, index) {
                                  Product product = items[index];
 
                                  Widget card; // สร้างเป็นตัวแปร
                                  card = Card(
                                      margin: const EdgeInsets.all(
                                          5.0), // การเยื้องขอบ
                                      child: Column(
                                        children: [
                                          ListTile(
                                            leading: CachedNetworkImage(
                                              imageUrl: product.image,
                                              width: 100.0,
                                              placeholder: (context, url) =>
                                                  Center(
                                                child: SizedBox(
                                                  // Adjust the size as needed
                                                  width: 40.0,
                                                  height: 40.0,
                                                  child:
                                                      CircularProgressIndicator(), // Show loading indicator
                                                ),
                                              ),
                                              errorWidget: (context, url,
                                                      error) =>
                                                  Icon(Icons
                                                      .error), // Show error icon if loading fails
                                            ),
                                            title: Text(product.title),
                                            subtitle: Text(
                                                'Price: \$ ${product.price}'),
                                            trailing: Icon(Icons.more_vert),
                                            onTap: () {},
                                          )
                                        ],
                                      ));
                                  return card;
                                },
                                separatorBuilder:
                                    (BuildContext context, int index) =>
                                        const SizedBox(),
                              ), 
                              // ใช้งาน ListView
 
 

การจัด Layout ด้วย ListView ไม่ใช้ ListTile จัดรูปแบบ

    เราสามารถจัดรูปแบบตามต้องการแทนการใช้งาน ListTile ได้ทำให้มีความหลากหลายมากขึ้น
 
                                // ใช้งาน ListView แบบกำหนดเอง ไม่ใช้ ListTile
                               child: ListView.separated(
                                // กรณีมีรายการ แสดงปกติ
                                controller:
                                    _scrollController, // กำนหนด controller ที่จะใช้งานร่วม
                                itemCount: items.length,
                                itemBuilder: (context, index) {
                                  Product product = items[index];
 
                                  Widget card; // สร้างเป็นตัวแปร
                                  card = Card(
                                      margin: const EdgeInsets.all(5.0), 
                                      child: Row(
                                        mainAxisAlignment:  MainAxisAlignment.start,
                                        crossAxisAlignment: CrossAxisAlignment.start,
                                        children: [
                                          Padding(
                                            padding: const EdgeInsets.all(8.0),
                                            child: CachedNetworkImage(
                                                imageUrl: product.image,
                                                height: 100.0,
                                                width: 100.0,
                                                fit: BoxFit.contain,
                                                placeholder: (context, url) =>
                                                    Center(
                                                  child: SizedBox(
                                                    // Adjust the size as needed
                                                    width: 40.0,
                                                    height: 40.0,
                                                    child: CircularProgressIndicator(), 
                                                  ),
                                                ),
                                                errorWidget: (context, url,error) =>Icon(Icons.error), 
                                              ),
                                          ),
                                            Expanded(
                                              child: Padding(
                                                padding: const EdgeInsets.all(0.0),
                                                child: Container(
                                                  color: Colors.grey[200],
                                                  child: Column(
                                                    mainAxisAlignment:  MainAxisAlignment.start,
                                                    crossAxisAlignment: CrossAxisAlignment.start,
                                                    children: [
                                                      Text(product.title),
                                                      Text('Price: \$ ${product.price}'),
                                                    ],
                                                  ),
                                                ),
                                              ),
                                            ),    
                                        ],
                                      ));
                                  return card;
                                },
                                separatorBuilder:(BuildContext context, int index) =>const SizedBox(),
                              ), 
                              // ใช้งาน ListView แบบกำหนดเอง ไม่ใช้ ListTile
 
 

การจัด Layout ด้วย GridView 

    จัดรูปแบบในลักษณะ Grid ที่มีความสูงของรายการข้อมูลเท่าๆ กัน
 
                              // ใช้งาน GridView
                               child: GridView.builder(
                              controller: _scrollController,
                              padding: const EdgeInsets.all(5.0),
                              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                                crossAxisCount: 2, // Number of columns
                                crossAxisSpacing: 0.0,
                                mainAxisSpacing: 0.0,
                                childAspectRatio: 3 / 3.8, // Adjust to control the size ratio
                              ),
                              itemCount: items.length,
                              itemBuilder: (context, index) {

                                Product product = items[index];
 
                                  Widget card; // สร้างเป็นตัวแปร
                                  card = Card(
                                      child: Padding(
                                        padding: const EdgeInsets.all(3.0),
                                        child: Column(
                                          crossAxisAlignment: CrossAxisAlignment.start,
                                          children: [
                                            Align(
                                              child: CachedNetworkImage(
                                                  imageUrl: product.image,
                                                  height: 150,
                                                  fit: BoxFit.contain,
                                                  placeholder: (context, url) =>
                                                      const Center(
                                                    child: SizedBox(
                                                      width: 40.0,
                                                      height: 40.0,
                                                      child:CircularProgressIndicator(), 
                                                    ),
                                                  ),
                                                  errorWidget: (context, url,
                                                          error) =>
                                                      const Icon(Icons.error), 
                                                ),
                                            ),
                                              Padding(
                                                padding: const EdgeInsets.all(3.0),
                                                child: Text(product.title,
                                                maxLines: 2,
                                                overflow: TextOverflow.ellipsis,),
                                              ),
                                              Padding(
                                                padding: const EdgeInsets.all(3.0),
                                                child: Text('Price: \$ ${product.price}'),
                                              ),
                                          ],
                                        ),
                                      ));
                                      return card;
                                  },
                                ), 
                                // ใช้งาน GridView
 

การจัด Layout ด้วย MasonryGridView

    จัดรูปแบบในลักษณะ Grid ที่มีความสูงของรายการข้อมูลเป็นไปตามเนื้อหาภายในของแต่ละรายการ
ทำให้ให้รายการดูมีลักษณะเด่นพิเศษตามชนิดข้อมูลของรายการนั้นๆ เช่น ถ้ารูปรายการนั้นใหญ่ก็อาจจะ
แสดงเด่นกว่ารายการอื่น 
 
                              // ใช้งาน MasonryGridView
                              child: MasonryGridView.builder(
                                controller: _scrollController,
                                padding: const EdgeInsets.all(5.0),
                                gridDelegate: SliverSimpleGridDelegateWithFixedCrossAxisCount(
                                  crossAxisCount: 2, // Number of columns
                                ),
                                itemCount: items.length,
                                itemBuilder: (context, index) {
                                  Product product = items[index];

                                  return Card(
                                    child: Padding(
                                      padding: const EdgeInsets.all(3.0),
                                      child: Column(
                                        crossAxisAlignment: CrossAxisAlignment.start,
                                        children: [
                                          CachedNetworkImage(
                                            imageUrl: product.image,
                                            fit: BoxFit.contain,
                                            placeholder: (context, url) => const Center(
                                              child: SizedBox(
                                                width: 40.0,
                                                height: 40.0,
                                                child: CircularProgressIndicator(),
                                              ),
                                            ),
                                            errorWidget: (context, url, error) => const Icon(Icons.error),
                                          ),
                                          Padding(
                                            padding: const EdgeInsets.all(3.0),
                                            child: Text(
                                              product.title,
                                              maxLines: 2,
                                              overflow: TextOverflow.ellipsis,
                                            ),
                                          ),
                                          Padding(
                                            padding: const EdgeInsets.all(3.0),
                                            child: Text('Price: \$ ${product.price}'),
                                          ),
                                        ],
                                      ),
                                    ),
                                  );
                                },
                              ),
                              // ใช้งาน MasonryGridView
 
    เพื่อให้เห็นภาพรวมของตัวอย่างโค้ด ให้ดูไฟล์ทั้งหมด ได้ดังนี้ ส่วนของโค้ด มีการจัดการต่างๆ เกี่ยวกับ
รายการสินค้า ในเนื้อหาที่ผ่านมา
 

ไฟล์ product.dart

import 'dart:async';
import 'dart:convert';
import 'dart:io';
 
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
// import 'package:intl/intl.dart'; // จัดรูปแบบวันทีและเวลา http://niik.in/1047
import 'package:cached_network_image/cached_network_image.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
 
import '../models/product_model.dart';
  
class Products extends StatefulWidget {
    static const routeName = '/product';
 
    const Products({Key? key}) : super(key: key);
  
    @override
    State<StatefulWidget> createState() {
        return _ProductsState();
    }
}
  
class _ProductsState extends State<Products> {
  // สร้างตัวแปรที่สามารถแจ้งเตือนการเปลี่ยนแปลงค่า
  final ValueNotifier<bool> _visible = ValueNotifier<bool>(false);
  // กำนหดตัวแปรข้อมูล products
  Future<List<Product>> _products = Future.value([]);
  // ตัว ScrollController สำหรับจัดการการ scroll ใน ListView
  final ScrollController _scrollController = ScrollController();
  // สำหรับป้องกันการเรียกโหลดข้อมูลซ้ำในทันที
  bool _isLoading = false;
 
  // จำลองใช้เป็นแบบฟังก์ชั่น ให้เสมือนดึงข้อมูลจาก server
  Future<String> fetchData() async {
    print("debug: do function");
    final response = await Future<String>.delayed(
      const Duration(seconds: 2),
      () {
        return 'Data Loaded \n${DateTime.now()}';
      },
    );
    return response;
  }
 
  Future<void> _refresh() async {
    if (_isLoading) return;
 
    _visible.value = true;
    try {
      setState(() {
        _isLoading = true;
        _products = fetchProduct(reload: true);
      });
    } catch (e) {
      throw Exception('error: ${e}');
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }
 
  @override
  void initState() {
    print("debug: Init");
    super.initState();
    _products = fetchProduct();
  }
 
  @override
  void dispose() {
    _scrollController.dispose();
    _visible.dispose(); // Dispose the ValueNotifier
    super.dispose();
  }
 
  @override
  Widget build(BuildContext context) {
    print("debug: build");
    return Scaffold(
      appBar: AppBar(
        title: Text('Product'),
        actions: [
          IconButton(
            onPressed: () async {
              if (!_isLoading && _visible.value == false) {
                _refresh();
              }
            },
            icon: const Icon(Icons.refresh_outlined),
          )
        ],
      ),
      body: ListView(
        padding: const EdgeInsets.all(0.0),
        children: [
          ValueListenableBuilder<bool>(
            valueListenable: _visible,
            builder: (context, visible, child) {
              return Visibility(
                visible: visible,
                child: const LinearProgressIndicator(
                  backgroundColor: Colors.white60,
                ),
              );
            },
          ),
          FutureBuilder<List<Product>>(
            // ชนิดของข้อมูล
            future: _products,
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {}
              if (snapshot.connectionState == ConnectionState.done) {
                WidgetsBinding.instance.addPostFrameCallback((_) {
                  // Change state after the build is complete
                  _visible.value = false;
 
                  if (_scrollController.hasClients) {
                    //เช็คว่ามีตัว widget ที่ scroll ได้หรือไม่ ถ้ามี
                    // เลื่อน scroll มาด้านบนสุด
                    _scrollController.animateTo(0,
                        duration: Duration(milliseconds: 500),
                        curve: Curves.fastOutSlowIn);
                  }
                });
              }
              if (snapshot.hasData) {
                // แสดงทั้งหมด
                final items = snapshot.data!.toList();
                // แสดงแค่ 10 รายการ
                // final items = snapshot.data!.take(10).toList();
                double statusBarHeight = MediaQuery.of(context).padding.top;
                double appBarHeight = kToolbarHeight; // Default height of the AppBar (56.0)
                double availableHeight = MediaQuery.of(context).size.height - statusBarHeight - appBarHeight - 80;
                print("debug: ${statusBarHeight+kToolbarHeight+80}");
                 
                return Column(
                  children: [
                    Container(
                      // สร้างส่วน header ของลิสรายการ
                      padding: const EdgeInsets.all(5.0),
                      decoration: BoxDecoration(
                        color: Colors.orange.withAlpha(100),
                      ),
                      child: Row(
                        children: [
                          Text(
                              'Total ${items.length} items'), // แสดงจำนวนรายการ
                        ],
                      ),
                    ),
                    SizedBox(
                      // ปรับความสูงขางรายการทั้งหมด  การ ลบค่า เพื่อให้ข้อมูลแสดงเต็มพื้นที่
                      // หากมี appbar ควรลบ 100 ถ้ามีส่วนอื่นเพิ่มให้บวกเพิ่มเข้าไป ตามเหมาะสม
                      // หากไม่มี appbar ควรลบพื้นที่ที่เพิ่มเข้ามาค่าอื่นๆ ตามเหมาะสม
                      height: MediaQuery.of(context).size.height - 136,
                      child: snapshot.data!.isNotEmpty // กำหนดเงื่อนไขตรงนี้
                          ? RefreshIndicator(
                              onRefresh: () async {
                                if (!_isLoading && _visible.value == false) {
                                  _refresh();
                                }
                              },
                              // ใช้งาน MasonryGridView
                              child: MasonryGridView.builder(
                                controller: _scrollController,
                                padding: const EdgeInsets.all(5.0),
                                gridDelegate: SliverSimpleGridDelegateWithFixedCrossAxisCount(
                                  crossAxisCount: 2, // Number of columns
                                ),
                                itemCount: items.length,
                                itemBuilder: (context, index) {
                                  Product product = items[index];

                                  return Card(
                                    child: Padding(
                                      padding: const EdgeInsets.all(3.0),
                                      child: Column(
                                        crossAxisAlignment: CrossAxisAlignment.start,
                                        children: [
                                          CachedNetworkImage(
                                            imageUrl: product.image,
                                            fit: BoxFit.contain,
                                            placeholder: (context, url) => const Center(
                                              child: SizedBox(
                                                width: 40.0,
                                                height: 40.0,
                                                child: CircularProgressIndicator(),
                                              ),
                                            ),
                                            errorWidget: (context, url, error) => const Icon(Icons.error),
                                          ),
                                          Padding(
                                            padding: const EdgeInsets.all(3.0),
                                            child: Text(
                                              product.title,
                                              maxLines: 2,
                                              overflow: TextOverflow.ellipsis,
                                            ),
                                          ),
                                          Padding(
                                            padding: const EdgeInsets.all(3.0),
                                            child: Text('Price: \$ ${product.price}'),
                                          ),
                                        ],
                                      ),
                                    ),
                                  );
                                },
                              ),
                              // ใช้งาน MasonryGridView

                              // ใช้งาน GridView
/*                               child: GridView.builder(
                              controller: _scrollController,
                              padding: const EdgeInsets.all(5.0),
                              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                                crossAxisCount: 2, // Number of columns
                                crossAxisSpacing: 0.0,
                                mainAxisSpacing: 0.0,
                                childAspectRatio: 3 / 3.8, // Adjust to control the size ratio
                              ),
                              itemCount: items.length,
                              itemBuilder: (context, index) {

                                Product product = items[index];
 
                                  Widget card; // สร้างเป็นตัวแปร
                                  card = Card(
                                      child: Padding(
                                        padding: const EdgeInsets.all(3.0),
                                        child: Column(
                                          crossAxisAlignment: CrossAxisAlignment.start,
                                          children: [
                                            Align(
                                              child: CachedNetworkImage(
                                                  imageUrl: product.image,
                                                  height: 150,
                                                  fit: BoxFit.contain,
                                                  placeholder: (context, url) =>
                                                      const Center(
                                                    child: SizedBox(
                                                      width: 40.0,
                                                      height: 40.0,
                                                      child:CircularProgressIndicator(), 
                                                    ),
                                                  ),
                                                  errorWidget: (context, url,
                                                          error) =>
                                                      const Icon(Icons.error), 
                                                ),
                                            ),
                                              Padding(
                                                padding: const EdgeInsets.all(3.0),
                                                child: Text(product.title,
                                                maxLines: 2,
                                                overflow: TextOverflow.ellipsis,),
                                              ),
                                              Padding(
                                                padding: const EdgeInsets.all(3.0),
                                                child: Text('Price: \$ ${product.price}'),
                                              ),
                                          ],
                                        ),
                                      ));
                                      return card;
                                  },
                                ), */
                                // ใช้งาน GridView

                                // ใช้งาน ListView แบบกำหนดเอง ไม่ใช้ ListTile
/*                               child: ListView.separated(
                                // กรณีมีรายการ แสดงปกติ
                                controller:
                                    _scrollController, // กำนหนด controller ที่จะใช้งานร่วม
                                itemCount: items.length,
                                itemBuilder: (context, index) {
                                  Product product = items[index];
 
                                  Widget card; // สร้างเป็นตัวแปร
                                  card = Card(
                                      margin: const EdgeInsets.all(5.0), 
                                      child: Row(
                                        mainAxisAlignment:  MainAxisAlignment.start,
                                        crossAxisAlignment: CrossAxisAlignment.start,
                                        children: [
                                          Padding(
                                            padding: const EdgeInsets.all(8.0),
                                            child: CachedNetworkImage(
                                                imageUrl: product.image,
                                                height: 100.0,
                                                width: 100.0,
                                                fit: BoxFit.contain,
                                                placeholder: (context, url) =>
                                                    Center(
                                                  child: SizedBox(
                                                    // Adjust the size as needed
                                                    width: 40.0,
                                                    height: 40.0,
                                                    child: CircularProgressIndicator(), 
                                                  ),
                                                ),
                                                errorWidget: (context, url,error) =>Icon(Icons.error), 
                                              ),
                                          ),
                                            Expanded(
                                              child: Padding(
                                                padding: const EdgeInsets.all(0.0),
                                                child: Container(
                                                  color: Colors.grey[200],
                                                  child: Column(
                                                    mainAxisAlignment:  MainAxisAlignment.start,
                                                    crossAxisAlignment: CrossAxisAlignment.start,
                                                    children: [
                                                      Text(product.title),
                                                      Text('Price: \$ ${product.price}'),
                                                    ],
                                                  ),
                                                ),
                                              ),
                                            ),    
                                        ],
                                      ));
                                  return card;
                                },
                                separatorBuilder:(BuildContext context, int index) =>const SizedBox(),
                              ), */
                              // ใช้งาน ListView แบบกำหนดเอง ไม่ใช้ ListTile                              

                                // ใช้งาน ListView
 /*                              child: ListView.separated(
                                // กรณีมีรายการ แสดงปกติ
                                controller:
                                    _scrollController, // กำนหนด controller ที่จะใช้งานร่วม
                                itemCount: items.length,
                                itemBuilder: (context, index) {
                                  Product product = items[index];
 
                                  Widget card; // สร้างเป็นตัวแปร
                                  card = Card(
                                      margin: const EdgeInsets.all(
                                          5.0), // การเยื้องขอบ
                                      child: Column(
                                        children: [
                                          ListTile(
                                            leading: CachedNetworkImage(
                                              imageUrl: product.image,
                                              width: 100.0,
                                              placeholder: (context, url) =>
                                                  Center(
                                                child: SizedBox(
                                                  // Adjust the size as needed
                                                  width: 40.0,
                                                  height: 40.0,
                                                  child:
                                                      CircularProgressIndicator(), // Show loading indicator
                                                ),
                                              ),
                                              errorWidget: (context, url,
                                                      error) =>
                                                  Icon(Icons
                                                      .error), // Show error icon if loading fails
                                            ),
                                            title: Text(product.title),
                                            subtitle: Text(
                                                'Price: \$ ${product.price}'),
                                            trailing: Icon(Icons.more_vert),
                                            onTap: () {},
                                          )
                                        ],
                                      ));
                                  return card;
                                },
                                separatorBuilder:
                                    (BuildContext context, int index) =>
                                        const SizedBox(),
                              ), */
                              // ใช้งาน ListView


                            )
                          : const Center(
                              child: Text('No items')), // กรณีไม่มีรายการ
                    ),
                  ],
                );
              } else if (snapshot.hasError) {
                return Center(child: Text('${snapshot.error}'));
              }
              return const Center(child: CircularProgressIndicator());
            },
          ),
        ],
      ),
      floatingActionButton: ValueListenableBuilder<bool>(
        valueListenable: _visible,
        builder: (context, visible, child) {
          return (visible == false)
              ? FloatingActionButton(
                  onPressed: () async {
                    if (!_isLoading && _visible.value == false) {
                      _refresh();
                    }
                  },
                  shape: const CircleBorder(),
                  child: const Icon(Icons.refresh),
                )
              : SizedBox.shrink();
        },
      ),
    );
  }
}
 
// สรัางฟังก์ชั่นดึงข้อมูล คืนค่ากลับมาเป็นข้อมูล Future ประเภท List ของ Product
Future<List<Product>> fetchProduct({reload}) async {
  String _currentPath = ''; // เก็บ path ปัจจุบัน
  final appDocumentsDirectory = await getApplicationDocumentsDirectory();
 
  _currentPath = appDocumentsDirectory.path;
 
  String filename = "product_cache.json";
  String readFile = "$_currentPath/$filename";
 
  String _jsonData = '';
  final _file = File(readFile);
  final isExits = await _file.exists();
 
  try {
    if (isExits && reload == null) {
      print("debug: read from file");
      _jsonData = await _file.readAsString();
      return compute(parseProducts, _jsonData);
    } else {
      // ทำการดึงข้อมูลจาก server ตาม url ที่กำหนด
      String url = 'https://fakestoreapi.com/products';
      final response = await http.get(Uri.parse(url));
 
      // เมื่อมีข้อมูลกลับมา
      if (response.statusCode == 200) {
        print("debug: load form server");
        final myfile = _file;
        final isExits = await myfile.exists(); // เช็คว่ามีไฟล์หรือไม่
        if (!isExits) {
          // ถ้ายังไม่มีไฟล์
          try {
            await myfile.writeAsString(response.body);
          } catch (e) {
            throw Exception('error: ${e}');
          }
        } else {
          try {
            await myfile.writeAsString(response.body);
          } catch (e) {
            throw Exception('error: ${e}');
          }
        }
        // ส่งข้อมูลที่เป็น JSON String data ไปทำการแปลง เป็นข้อมูล List<Product
        // โดยใช้คำสั่ง compute ทำงานเบื้องหลัง เรียกใช้ฟังก์ชั่นชื่อ parseProducts
        // ส่งข้อมูล JSON String data ผ่านตัวแปร response.body
        return compute(parseProducts, response.body);
      } else {
        // กรณี error
        throw Exception('Failed to load product');
      }
    }
  } catch (e) {
    throw Exception('error: ${e}');
  }
}
 
// ฟังก์ชั่นแปลงข้อมูล JSON String data เป็น เป็นข้อมูล List<Product>
List<Product> parseProducts(String responseBody) {
  final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
  return parsed.map<Product>((json) => Product.fromJson(json)).toList();
}
 
 
    ตัวอย่างและแนวทางโค้ดทั้งหมดนี้ สามารถนำไปประยุกต์ใช้งานได้ทันที และปรับแต่งได้ตามต้องการ
ในโค้ดจะมีแนวทางความรู้ต่างๆ ผสมปะปนอยู่ หวังว่าเนื้อหานี้จะสามารถนำไปต่อยอดไม่มากก็น้อย


   เพิ่มเติมเนื้อหา ครั้งที่ 1 วันที่ 02-09-2024


ดาวน์โหลดโค้ดตัวอย่าง สามารถนำไปประยุกต์ หรือ run ทดสอบได้

http://niik.in/download/flutter/demo_039_02092024_source.rar





อ่านต่อที่บทความ



ทบทวนบทความที่แล้ว









เนื้อหาที่เกี่ยวข้อง






เนื้อหาพิเศษ เฉพาะสำหรับสมาชิก

กรุณาล็อกอิน เพื่ออ่านเนื้อหาบทความ

ยังไม่เป็นสมาชิก

สมาชิกล็อกอิน



( หรือ เข้าใช้งานผ่าน Social Login )




URL สำหรับอ้างอิง








เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ