เนื้อหานี้จะเป็นแนวทางการประยุกต์ การดึงข้อมูล API
ของรุปภาพมาแสดงแบบ gallery ด้วย GridView และ
สามารถเปิดเลือกดูแต่ละรูปที่ต้องการได้ สามารถนำไป
ปรับใช้กรณีต้องการให้ app มีหน้า gallery รวมรูปภาพ
เนื้อหานี้เป็นการใช้แนวทางจากบทความที่เคยอธิบายไปแล้ว
ไม่ว่าจะเป็น การใช้งาน Http ดึงข้อมูลจาก Server หรือ
การใช้งาน GridView widget สามารถทบทวนได้ที่บทความ
การใช้งาน Http ดึงข้อมูลจาก Server มาแสดงใน Flutter http://niik.in/1038
https://www.ninenik.com/content.php?arti_id=1038 via @ninenik
การใช้งาน GridView widget ใน Flutter http://niik.in/1042
https://www.ninenik.com/content.php?arti_id=1042 via @ninenik
*เนื้อหานี้ใช้เนื้อหาต่อเนื่องจากบทความ http://niik.in/1070
ตัวอย่างผลลัพธ์และการทำงาน
เราสร้างหน้าใหม่มาแล้วเพิ่มเข้าไปใน sidemenu ชื่อว่า gallery เมื่อเปิดไปยังหน้า gallery เราก็จะทำการ
ไปเรียกข้อมูลรูปภาพจาก api ของเว็บไซต์ unsplash.com สามารถเข้าไปสมัครสมาชิกแล้วใช้งาน api ได้
หรือจะสะดวกสร้างขึ้นมาเองก็ได้หากเข้าใจหลักการ
เมื่อข้อมูลรูปภาพจาก api โหลดมาแล้วก็ทำการแสดงใน GridView widget โดยแสดงในลักษณะให้เต็ม
พื้นที่ของข้อมูลตามตัวอย่าง เมื่อเรากดเลือกจะดูรูปไหน ก็จะแสดงรูปนั้นขึ้นมาพร้อมที่สามารถปัดลงเพื่อปิด
หรือจะกดปุ่มปิดตรงมุมซ้ายก็ได้ แนวทางเบื้องต้นก็จะประมาณนี้
ขั้นตอนการสร้าง Photo Gallery
เริ่มต้นเราสร้างไฟล์ gallery.dart ไว้ในโฟลเดอร์ screens
lib > screens > gallery.dart *ใช้เนื้อหาต่อเนื่องจากบทความ http://niik.in/960
ไฟล์ gallery.dart
import 'package:flutter/material.dart'; class Gallery extends StatefulWidget { static const routeName = '/gallery'; const Gallery({Key? key}) : super(key: key); @override State<StatefulWidget> createState() { return _GalleryState(); } } class _GalleryState extends State<Gallery> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Gallery'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Gallery Screen'), ], ) ), ); } }
จากนั้นเพิ่มเมนูเข้าไปใน sidemenu
lib > components > sidemenu.dart
ไฟล์ sidemenu.dart บางส่วนเฉพาะที่เพิ่มเมนู
... ListTile( leading: Icon(FontAwesomeIcons.photoVideo), title: Text('Gallery'), onTap: () { Navigator.pushNamed( context, Gallery.routeName ); }, ), ....
จากนั้นเพิ่ม route ใหม่ของ gallery ในไฟล์ main.dart
lib > main.dart
ไฟล์ main.dart บางส่วนเฉพาะที่เพิ่ม gallery
... routes: { Home.routeName: (context) => Home(), About.routeName: (context) => About(), Profile.routeName: (context) => Profile(), Contact.routeName: (context) => Contact(), Gallery.routeName: (context) => Gallery(), Settings.routeName: (context) => Settings(), }, ...
การเพิ่มหน้า app ไหม่สามารถทบทวนที่บทความ http://niik.in/960
ถ้าไม่มีอะไรผิดพลาดก็จะได้หน้าตา และการใช้งานเบื้องต้นดังนี้
ต่อไปให้ปรับแก้ไฟล์ gallery.dart ใหม่ดังนี้
// สร้าง List ของ url ภาพที่จะนำมาแสดง List<String> _photos = []; // ตัว ScrollController สำหรับจัดการการ scroll ใน GridView final ScrollController _scrollController = ScrollController();
เพิ่มส่วนของตัวแปรสำหรับเก็บ url ของรูปในแบบ List<String> และตัวแปรสำหรับจัดการ
ScrollController มีในบทความก่อนๆ
ต่อไปเป็นฟังก์ชั่นสำหรับดึงข้อมูล
// สรัางฟังก์ชั่นดึงข้อมูล คืนค่ากลับมาเป็นข้อมูล Future ประเภท List ของ String Future<List<String>> getPhotos() async { _photos.clear(); // ล้างข้อมูลเดิมถ้ามี try{ // ใช้งาน api ของ unsplash.com เปลี่ยนค่า client_id เป็นของเรา final response = await http .get(Uri.parse('https://api.unsplash.com/photos/?client_id=ค่าของเราเอง')); // เมื่อมีข้อมูลกลับมา if (response.statusCode == 200) { // แปลงข้อมูล JSON String data เป็น List<dynamic> var _result = await json.decode(response.body); // วนลูปข้อมูล _result.forEach((ele){ // เอาเฉพาะข้อมูล url รุปภาพไม่่เพิ่มในตัวแปร _photos _photos.add(ele['urls']['regular']); }); } }catch(e){ print(e); } return _photos; } // ฟังก์ชั่นสำหรับ รีเฟรสโดยการดึงจากขอบบนลง มีอธิบานในบทความก่อนๆ หน้า Future<void> _refresh() async { _photos.clear(); // ล้างข้อมูลเดิมถ้ามี _photos = await getPhotos(); // ดึง url รูปใหม่ setState(() {}); }
คำสั่ง _refresh() เป็นการเรียกให้ฟังก์ชั่น getPhotos() ทำงานอีกครั้ง
ไฟล์ gallery.dart
import 'dart:async'; // สำหรับจัดการข้อมูลแบบ async import 'dart:convert'; // สำหรับจัดการข้อมูล JSON data import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; // ดึงข้อมูลจัดการข้อมูลบนเครือข่าย internet class Gallery extends StatefulWidget { static const routeName = '/gallery'; const Gallery({Key? key}) : super(key: key); @override State<StatefulWidget> createState() { return _GalleryState(); } } class _GalleryState extends State<Gallery> { // สร้าง List ของ url ภาพที่จะนำมาแสดง List<String> _photos = []; // ตัว ScrollController สำหรับจัดการการ scroll ใน GridView final ScrollController _scrollController = ScrollController(); @override void initState() { // TODO: implement initState super.initState(); } @override void dispose() { _scrollController.dispose(); super.dispose(); } // สรัางฟังก์ชั่นดึงข้อมูล คืนค่ากลับมาเป็นข้อมูล Future ประเภท List ของ String Future<List<String>> getPhotos() async { _photos.clear(); // ล้างข้อมูลเดิมถ้ามี try{ // ใช้งาน api ของ unsplash.com เปลี่ยนค่า client_id เป็นของเรา final response = await http .get(Uri.parse('https://api.unsplash.com/photos/?client_id=abc')); // เมื่อมีข้อมูลกลับมา if (response.statusCode == 200) { // แปลงข้อมูล JSON String data เป็น List<dynamic> var _result = await json.decode(response.body); // วนลูปข้อมูล _result.forEach((ele){ // เอาเฉพาะข้อมูล url รุปภาพไม่่เพิ่มในตัวแปร _photos _photos.add(ele['urls']['regular']); }); } }catch(e){ print(e); } return _photos; } // ฟังก์ชั่นสำหรับ รีเฟรสโดยการดึงจากขอบบนลง มีอธิบานในบทความก่อนๆ หน้า Future<void> _refresh() async { _photos.clear(); // ล้างข้อมูลเดิมถ้ามี _photos = await getPhotos(); // ดึง url รูปใหม่ setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Gallery'), ), body: Center( child: FutureBuilder<List<String>>( // ชนิดของข้อมูล future: getPhotos(), // ข้อมูล Future builder: (context, snapshot) { // มีข้อมูล และต้องเป็น done ถึงจะแสดงข้อมูล ถ้าไม่ใช่ ก็แสดงตัว loading if (snapshot.hasData) { bool _visible = false; // กำหนดสถานะการแสดง หรือมองเห็น เป็นไม่แสดง if(snapshot.connectionState == ConnectionState.waiting){ // เมื่อกำลังรอข้อมูล _visible = true; // เปลี่ยนสถานะเป็นแสดง } if(_scrollController.hasClients){ //เช็คว่ามีตัว widget ที่ scroll ได้หรือไม่ ถ้ามี // เลื่อน scroll มาด้านบนสุด _scrollController.animateTo(0, duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn); } return Column( children: [ Visibility( child: const LinearProgressIndicator(), visible: _visible, ), Container( // สร้างส่วน header ของลิสรายการ padding: const EdgeInsets.all(5.0), decoration: BoxDecoration( color: Colors.orange.withAlpha(100), ), child: Row( children: [ Text('Total ${snapshot.data!.length} items'), // แสดงจำนวนรายการ ], ), ), Expanded( // ส่วนของลิสรายการ child: snapshot.data!.isNotEmpty // กำหนดเงื่อนไขตรงนี้ ? RefreshIndicator( onRefresh: _refresh, child: Padding( padding: const EdgeInsets.all(0.0), child: GridView.builder( controller: _scrollController, // กำนหนด controller ที่จะใช้งานร่วม gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, ), itemCount: snapshot.data!.length, itemBuilder: (BuildContext context, int index) { var photo = snapshot.data![index]; Widget card; // สร้างเป็นตัวแปร card = Container( child: InkWell( onTap: (){ Navigator.of(context).push(_viewPhoto(context, photo)); }, child: Card( // color: Colors.black, child: Column( children: [ AspectRatio( aspectRatio: 1.0, child: Container( decoration: BoxDecoration( image: DecorationImage( image: NetworkImage(photo), fit: BoxFit.cover, ), // color: Colors.black, ), // child: Image.network(photo), ), ), ], ), ), ) ); return card; }, ), ), ) : const Center(child: Text('No items')), // กรณีไม่มีรายการ ), ], ); } else if (snapshot.hasError) { // กรณี error return Text('${snapshot.error}'); } // กรณีสถานะเป็น waiting ยังไม่มีข้อมูล แสดงตัว loading return const RefreshProgressIndicator(); }, ), ), ); } // สร้างฟังก์ชั่น ที่คืนค่าเป็น route ของ object ฟังก์ชั่นนี้ มี context และ photo เป็น parameter static Route<Object?> _viewPhoto(BuildContext context, photo) { return DialogRoute<void>( context: context, builder: (BuildContext context) => // ใช้ arrow aฟังก์ชั่น Dismissible( // คืนค่าเป็น dismissible widget direction: DismissDirection.vertical, // เมื่อปัดลงในแนวตั้ง key: const Key('key'), // ต้องกำหนด key ใช้ค่าตามนี้ได้เลย onDismissed: (_) => Navigator.of(context).pop(), // ปัดลงเพื่อปิด child: Scaffold( backgroundColor: Colors.black, extendBodyBehindAppBar: true, // แสดงพื้นที่ appbar แยก ให้ขายเต็มจอ appBar: AppBar( leading: IconButton( onPressed: (){ Navigator.of(context).pop(); }, icon: Icon(Icons.close,color: Colors.white), ), backgroundColor: Colors.transparent, elevation: 0.0, ), body: Center( child: Container( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(8.0), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Image.network(photo), // แสดงรูปจาก url รูปที่ส่งเข้ามา ], ), ), ) ), ), ), ), ); } }
จุดที่น่าสนใจคือ เราทำการกำหนดให้รุปที่ดึงมา แสดงเป็น background ของ Container
ดูส่วนของโค้ดบรรทัดนี้
child: Container( decoration: BoxDecoration( image: DecorationImage( image: NetworkImage(photo), // รูปที่จะแสดง fit: BoxFit.cover, // กำหนดให้แสดงคลุมเต็มพื้นที่รูปจะโดน crop ไปบ้าง ), // color: Colors.black, ), // child: Image.network(photo), ),
ผลลัพธ์หน้า gallery
เราลองเปลี่ยนใช้ตัวที่คอมเม้นท์ปิดไว้แทน ก็จะเป็น
child: Container( decoration: BoxDecoration( /* image: DecorationImage( image: NetworkImage(photo), // รูปที่จะแสดง fit: BoxFit.cover, // กำหนดให้แสดงคลุมเต็มพื้นที่รูปจะโดน crop ไปบ้าง ), */ color: Colors.black, ), child: Image.network(photo), ),
ผลลัพธ์หน้า gallery
แบบที่สองจะเป็นการแทรกรูปเข้าไปใน Container โดยไม่ได้กำหนดใช้เป็นพื้นหลัง ดังนั้นขนาด
ของรุปที่แสดงก็จะเห็นรายละเอียดรุปทั้งหมด แต่ก็จะมีช่องว่างของขอบรูป ที่ขนาดของรุปไม่สอด
คล้องกับพื้นที่แสดง และเราแทนพื้นหลังเป็นสีดำ
แบบพื้นหลังเราก็ได้ GridView ที่แสดงรุปสวยงาม ในขณะที่แบบไม่ใช้พื้นหลังเราก็จะได้ GridView
ที่ได้รายละเอียดของ รู้ว่าเป็นรูปแนวตั้งหรือแนวนอน จุดนี้เราสามารถเลือกใช้ได้ ในตัวอย่างเราจะใช้เป็น
แบบพื้นหลัง และรูปแสดงเต็มพื้นที่ในช่อง Grid
ต่อไปเราจะประยุกต์เพิ่มเติมอีกเล็กน้อย คือเดิม เวลาเราเลือกดูรูปใดๆ แล้ว เราต้องปิดรูปนั้นลงมาก่อน
แล้วก็กดเลือกรูปใหม่ เพราะตอนแสดงรูป เราส่งแค่รูปเดียวไปแสดง ทีนี้เราจะเปลี่ยนเป็นส่งรูปทั้งหมด
ไปแสดงใน PageView ซึ่งตัว PageView เราสามารถกำหนดให้สามารถปัดเลื่อนบนล่าง หรือซ้ายขวา
เพื่อดูรายการต่อๆ ไป โดยไม่ต้องปิด แล้วเปิดใหม่
สิ่งที่เราต้องกำหนดเพิ่มคือ
int _currentPhoto = 0; // ตัวแปรเก็บ index รูปที่เลือกดู
เมื่อกดที่รูปไหน ก็ให้เก็บ index ค่านั้นไว้ในตัวแปรนี้
onTap: () { _currentPhoto = index; // เก็บ index ที่กดดูรุป Navigator.of(context).push(_viewPhoto(context, photos)); },
สังเกตว่าเดิมเราส่งแค่รูปเดียวไปแสดง
var photo = snapshot.data![index]; Navigator.of(context).push(_viewPhoto(context, photo));
ก็เปลี่ยนเป็นส่งรูปทั้งหมดไปแสดง แล้วค่อยใช้ค่า _currentPhoto บอกว่าให้รูปไหนเริ่มต้น
var photos = snapshot.data!; Navigator.of(context).push(_viewPhoto(context, photos));
เมื่อเปิดหน้ารูปภาพมาแล้ว ก็จะแสดงรูปที่เรากำหนดในค่า _currentPhoto แล้วก็สามารถเลื่อนดู
รูปอื่นๆ ได้ ดูตัวอย่างการประยุกต์ ส่วนของการแสดง ก็จะเป็นดังนี้
// สร้างฟังก์ชั่น ที่คืนค่าเป็น route ของ object ฟังก์ชั่นนี้ มี context และ photos เป็น parameter Route<Object?> _viewPhoto(BuildContext context, photos) { return DialogRoute<void>( context: context, builder: (context){ return Dismissible( // คืนค่าเป็น dismissible widget direction: DismissDirection.vertical, // เมื่อปัดลงในแนวตั้ง key: const Key('key'), // ต้องกำหนด key ใช้ค่าตามนี้ได้เลย onDismissed: (_) => Navigator.of(context).pop(), // ปัดลงเพื่อปิด child: Scaffold( backgroundColor: Colors.black, extendBodyBehindAppBar: true, // แสดงพื้นที่ appbar แยก ให้ขายเต็มจอ appBar: AppBar( leading: IconButton( onPressed: (){ Navigator.of(context).pop(); }, icon: Icon(Icons.close,color: Colors.white), ), backgroundColor: Colors.transparent, elevation: 0.0, ), body: PageView.builder( scrollDirection: Axis.horizontal, // ปัดเลื่อนในแนวนอน controller: PageController(initialPage:_currentPhoto), // รูปแรกที่แสดง itemCount: photos.length, // จำนวนรูปทั้งหมด itemBuilder: (context, _index){ // วนลูปสร้างรูปที่จะแสดงทั้งหมด return Image.network(photos[_index]); } ), ), ); }, ); }
ดูผลลัพธ์และการทำงาน
ตอนนี้เราสามารถเลือกรูปที่ต้องการจะเปิด และสามารถเลื่อนดูรูปอืนๆ ต่อได้โดยที่ไม่ต้องปิดลงมา
แล้วเลือกใหม่ ทำให้ใช้งานสะดวกขึ้น
ไฟล์ gallery.dart
import 'dart:async'; // สำหรับจัดการข้อมูลแบบ async import 'dart:convert'; // สำหรับจัดการข้อมูล JSON data import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; // ดึงข้อมูลจัดการข้อมูลบนเครือข่าย internet class Gallery extends StatefulWidget { static const routeName = '/gallery'; const Gallery({Key? key}) : super(key: key); @override State<StatefulWidget> createState() { return _GalleryState(); } } class _GalleryState extends State<Gallery> { // สร้าง List ของ url ภาพที่จะนำมาแสดง List<String> _photos = []; // ตัว ScrollController สำหรับจัดการการ scroll ใน GridView final ScrollController _scrollController = ScrollController(); int _currentPhoto = 0; // รูปที่เลือกดู @override void initState() { // TODO: implement initState super.initState(); } @override void dispose() { _scrollController.dispose(); super.dispose(); } // สรัางฟังก์ชั่นดึงข้อมูล คืนค่ากลับมาเป็นข้อมูล Future ประเภท List ของ String Future<List<String>> getPhotos() async { _photos.clear(); // ล้างข้อมูลเดิมถ้ามี try{ // ใช้งาน api ของ unsplash.com เปลี่ยนค่า client_id เป็นของเรา final response = await http .get(Uri.parse('https://api.unsplash.com/photos/?client_id=abc')); // เมื่อมีข้อมูลกลับมา if (response.statusCode == 200) { // แปลงข้อมูล JSON String data เป็น List<dynamic> var _result = await json.decode(response.body); // วนลูปข้อมูล _result.forEach((ele){ // เอาเฉพาะข้อมูล url รุปภาพไม่่เพิ่มในตัวแปร _photos _photos.add(ele['urls']['regular']); }); } }catch(e){ print(e); } return _photos; } // ฟังก์ชั่นสำหรับ รีเฟรสโดยการดึงจากขอบบนลง มีอธิบานในบทความก่อนๆ หน้า Future<void> _refresh() async { _photos.clear(); // ล้างข้อมูลเดิมถ้ามี _photos = await getPhotos(); // ดึง url รูปใหม่ setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Gallery'), ), body: Center( child: FutureBuilder<List<String>>( // ชนิดของข้อมูล future: getPhotos(), // ข้อมูล Future builder: (context, snapshot) { // มีข้อมูล และต้องเป็น done ถึงจะแสดงข้อมูล ถ้าไม่ใช่ ก็แสดงตัว loading if (snapshot.hasData) { bool _visible = false; // กำหนดสถานะการแสดง หรือมองเห็น เป็นไม่แสดง if(snapshot.connectionState == ConnectionState.waiting){ // เมื่อกำลังรอข้อมูล _visible = true; // เปลี่ยนสถานะเป็นแสดง } if(_scrollController.hasClients){ //เช็คว่ามีตัว widget ที่ scroll ได้หรือไม่ ถ้ามี // เลื่อน scroll มาด้านบนสุด _scrollController.animateTo(0, duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn); } return Column( children: [ Visibility( child: const LinearProgressIndicator(), visible: _visible, ), Container( // สร้างส่วน header ของลิสรายการ padding: const EdgeInsets.all(5.0), decoration: BoxDecoration( color: Colors.orange.withAlpha(100), ), child: Row( children: [ Text('Total ${snapshot.data!.length} items'), // แสดงจำนวนรายการ ], ), ), Expanded( // ส่วนของลิสรายการ child: snapshot.data!.isNotEmpty // กำหนดเงื่อนไขตรงนี้ ? RefreshIndicator( onRefresh: _refresh, child: Padding( padding: const EdgeInsets.all(0.0), child: GridView.builder( controller: _scrollController, // กำนหนด controller ที่จะใช้งานร่วม gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, ), itemCount: snapshot.data!.length, itemBuilder: (BuildContext context, int index) { var photos = snapshot.data!; var photo = snapshot.data![index]; Widget card; // สร้างเป็นตัวแปร card = Container( child: InkWell( onTap: () { _currentPhoto = index; Navigator.of(context).push(_viewPhoto(context, photos)); }, child: Card( // color: Colors.black, child: Column( children: [ AspectRatio( aspectRatio: 1.0, child: Container( decoration: BoxDecoration( image: DecorationImage( image: NetworkImage(photo), fit: BoxFit.cover, ), // color: Colors.black, ), // child: Image.network(photo), ), ), ], ), ), ) ); return card; }, ), ), ) : const Center(child: Text('No items')), // กรณีไม่มีรายการ ), ], ); } else if (snapshot.hasError) { // กรณี error return Text('${snapshot.error}'); } // กรณีสถานะเป็น waiting ยังไม่มีข้อมูล แสดงตัว loading return const RefreshProgressIndicator(); }, ), ), ); } // สร้างฟังก์ชั่น ที่คืนค่าเป็น route ของ object ฟังก์ชั่นนี้ มี context และ photos เป็น parameter Route<Object?> _viewPhoto(BuildContext context, photos) { return DialogRoute<void>( context: context, builder: (context){ return Dismissible( // คืนค่าเป็น dismissible widget direction: DismissDirection.vertical, // เมื่อปัดลงในแนวตั้ง key: const Key('key'), // ต้องกำหนด key ใช้ค่าตามนี้ได้เลย onDismissed: (_) => Navigator.of(context).pop(), // ปัดลงเพื่อปิด child: Scaffold( backgroundColor: Colors.black, extendBodyBehindAppBar: true, // แสดงพื้นที่ appbar แยก ให้ขายเต็มจอ appBar: AppBar( leading: IconButton( onPressed: (){ Navigator.of(context).pop(); }, icon: Icon(Icons.close,color: Colors.white), ), backgroundColor: Colors.transparent, elevation: 0.0, ), body: PageView.builder( scrollDirection: Axis.horizontal, // ปัดเลื่อนในแนวนอน controller: PageController(initialPage:_currentPhoto), // รูปแรกที่แสดง itemCount: photos.length, // จำนวนรูปทั้งหมด itemBuilder: (context, _index){ // วนลูปสร้างรูปที่จะแสดงทั้งหมด return Image.network(photos[_index]); } ), ), ); }, ); } }
เท่านี้เราก็สามารถสร้าง photo gallery จากการใช้งานรูปบน server มาแสดงใน app ของเราได้
แนวทางนี้ใช้รูปจาก api ของ unsplash.com ดังนั้นเวลานำไปปรับใช้ ให้ดูเรื่องของการกำหนดรุปแบบ
ข้อมุลที่ได้มาจะต้องเป็น List<String> หรือ url ของรูปภาพ ตัวอย่าง JSON String data ของเว็บไซต์
เป็น https://www.ninenik.com/demo/article_api.php
ก็สามารถกำหนดเป็นดังนี้
// สรัางฟังก์ชั่นดึงข้อมูล คืนค่ากลับมาเป็นข้อมูล Future ประเภท List ของ String Future<List<String>> getPhotos() async { _photos.clear(); // ล้างข้อมูลเดิมถ้ามี try{ final response = await http .get(Uri.parse('https://www.ninenik.com/demo/article_api.php')); // เมื่อมีข้อมูลกลับมา if (response.statusCode == 200) { // แปลงข้อมูล JSON String data เป็น List<dynamic> var _result = await json.decode(response.body); // วนลูปข้อมูล _result.forEach((ele){ // เอาเฉพาะข้อมูล url รุปภาพไม่่เพิ่มในตัวแปร _photos _photos.add(ele['img']); }); } }catch(e){ print(e); } return _photos; }
ผลลัพธ์ก็จะประมาณนี้
หวังว่าเนื้อหานี้จะสามารถเป็นแนวทางนำไปปรับประยุกต์ใช้งานต่อไป ตอนหน้าจะเป็นอะไร รอติดตาม