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

บทความใหม่ เดือนที่แล้ว โดย Ninenik Narkdee
layout product listview masonrygridview gridview

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

ดูแล้ว 213 ครั้ง


เนื้อหาตอนต่อไปนี้ จะนำตัาอย่างแนวทางการจัดรูปแบบการแสดง
รายการสินค้าในแบบต่างๆ ให้สามารถนำไปใช้งานหรือประยุกต์ต่อได้
จะเป็นเนื้อหาที่ต่อยอดจากบทความ ตามลิ้งค์ด้านล่าง
 
การ 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


กด Like หรือ Share เป็นกำลังใจ ให้มีบทความใหม่ๆ เรื่อยๆ น่ะครับ



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



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









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






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

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

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

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



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




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





คำแนะนำ และการใช้งาน

สมาชิก กรุณา ล็อกอินเข้าระบบ เพื่อตั้งคำถามใหม่ หรือ ตอบคำถาม สมาชิกใหม่ สมัครสมาชิกได้ที่ สมัครสมาชิก


  • ถาม-ตอบ กรุณา ล็อกอินเข้าระบบ
  • เปลี่ยน


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







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