Halo teman - teman pada artikel kali ini kita akan melanjutkan tutorialnya, setelah kalian sudah install depedensi dan konfigurasi untuk komunikasi rest API, langkah selanjutnya yaitu kita akan menampilkan data tesebut.
Langkah 1 - Buat Layout Post
Sekarang teman - teman buat file dengan nama post_view.dart
pada folder component
, lalu kalian buat class dengan nama PostView
dengan extends StatelessWidget
, kalian bisa ketik aja stl nanti akan muncul sugest untuk pembuat class seperti gambar berikut:
lalu lengkapi kode berikut:
import 'package:flutter/material.dart';
import 'package:flutter_pemula/model/post.dart';
class PostView extends StatelessWidget {
final Post post;
const PostView({
super.key,
required this.post,
});
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.network(
post.image,
height: 150,
width: 150,
fit: BoxFit.cover,
),
const SizedBox(
width: 16,
),
Expanded(
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
post.title,
maxLines: 1,
style: Theme.of(context).textTheme.bodyLarge,
),
Text(post.content),
],
),
)
],
);
}
}
Langkah 2 - Membuat Tampilan Home
Setelah kalian sudah membuat tampilan post sekarang kita membuat screen untuk menampilkan data dari json, sekarang kita buat class dengan nama home.dart
pada folder screen
, lalu kalian buat class dengan nama Home
dengan extends StatefulWidget
.
Perhatian:
Apa perbedaan StatelessWidget
dengan StatefulWidget
secara singkat StatelessWidget
adalah widget yang besifat tidak berubah immutable. Artinya, sekali widget ini dibuat, ia tidak akan berubah selama siklus hidupnya. Sedangkan, StatefulWidget
adalah widget yang bersifat dapat berubah mutable. Artinya, widget ini bisa berubah selama siklus hidupnya melalui perubahan state (keadaan).
Ketik kode berikut:
import 'package:flutter/material.dart';
class Home extends StatefulWidget {
const Home({super.key});
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}
Lagkah 3 - Membuat Request GET Data dari API
Langkah selajutnya buat request get data dari API lalu di tampilkan, sehingga kode secara lengkap menjadi berikut:
import 'package:flutter/material.dart';
import 'package:flutter_pemula/api/repository.dart';
import 'package:flutter_pemula/component/post_view.dart';
import 'package:flutter_pemula/model/post.dart';
class Home extends StatefulWidget {
final String title;
const Home({
super.key,
required this.title,
});
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
final ScrollController _scrollController = ScrollController();
final Repository _apiService = Repository();
final List<Post> _posts = [];
bool _isLoading = false;
bool _hasMore = true;
int _currentPage = 1;
@override
void initState() {
super.initState();
_loadPosts();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_loadMorePosts();
}
});
}
Future<void> _loadPosts() async {
setState(() {
_isLoading = true;
});
try {
final result = await _apiService.fetchPosts(_currentPage);
setState(() {
_currentPage++;
_posts.addAll(result['posts']);
_hasMore = result['nextPageUrl'] != null;
});
} catch (e) {
throw Exception(e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
Future<void> _loadMorePosts() async {
if (_isLoading || !_hasMore) return;
setState(() {
_isLoading = true;
});
try {
final result = await _apiService.fetchPosts(_currentPage);
setState(() {
_currentPage++;
_posts.addAll(result['posts']);
_hasMore = result['nextPageUrl'] != null;
});
} catch (e) {
throw Exception(e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: _buildPostList(),
floatingActionButton: FloatingActionButton(
onPressed: () {
//TODO action to add and edit post
},
child: const Icon(Icons.add),
),
);
}
Widget _buildPostList() {
return ListView.builder(
controller: _scrollController,
itemCount: _posts.length + (_hasMore ? 1 : 0),
itemBuilder: (context, index) {
if (index == _posts.length) {
return const Center(child: CircularProgressIndicator());
}
final post = _posts[index];
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card.filled(
clipBehavior: Clip.hardEdge,
child: InkWell(
onTap: () {
// Todo action ke detail post
},
child: Stack(
children: [
PostView(post: post),
Positioned(
top: 2,
right: 2,
child: IconButton(
onPressed: () {
// TODO action to edit post
},
icon: const Icon(Icons.edit_rounded),
),
),
Positioned(
bottom: 2,
right: 2,
child: IconButton(
onPressed: () {
//TODO action delete post
},
icon: const Icon(Icons.delete_rounded),
),
)
],
),
),
),
);
},
);
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
}
Berikut adalah penjelasan kode yang diberikan:
Import Packages
import 'package:flutter/material.dart';
import 'package:flutter_pemula/api/repository.dart';
import 'package:flutter_pemula/component/post_view.dart';
import 'package:flutter_pemula/model/post.dart';
-
flutter/material.dart
: Mengimpor paket Flutter dasar untuk membangun antarmuka pengguna (UI).
-
flutter_pemula/api/repository.dart
: Mengimpor file repository.dart
yang berisi kelas untuk mengambil data dari API.
-
flutter_pemula/component/post_view.dart
: Mengimpor file post_view.dart
yang berisi widget untuk menampilkan post.
-
flutter_pemula/model/post.dart
: Mengimpor file post.dart
yang berisi model data Post
.
Home Widget
class Home extends StatefulWidget {
final String title;
const Home({
super.key,
required this.title,
});
@override
State<Home> createState() => _HomeState();
}
-
Home
adalah StatefulWidget
yang menerima title
sebagai parameter.
-
State<Home>
adalah state yang terkait dengan widget Home
.
_HomeState
class _HomeState extends State<Home> {
final ScrollController _scrollController = ScrollController();
final Repository _apiService = Repository();
final List<Post> _posts = [];
bool _isLoading = false;
bool _hasMore = true;
int _currentPage = 1;
-
_scrollController
: Untuk mengontrol scroll pada list view.
-
_apiService
: Instance dari Repository
untuk mengambil data dari API.
-
_posts
: List yang menyimpan post yang diambil dari API.
-
_isLoading
: Boolean yang menunjukkan apakah sedang mengambil data.
-
_hasMore
: Boolean yang menunjukkan apakah masih ada data yang bisa diambil.
-
_currentPage
: Menyimpan nomor halaman saat ini untuk paginasi.
initState
@override
void initState() {
super.initState();
_loadPosts();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_loadMorePosts();
}
});
}
-
initState
: Dipanggil sekali saat widget dibuat. Mengambil data post awal dan menambahkan listener untuk mendeteksi ketika mencapai bagian bawah list untuk mengambil lebih banyak post.
_loadPosts dan _loadMorePosts
Future<void> _loadPosts() async {
setState(() {
_isLoading = true;
});
try {
final result = await _apiService.fetchPosts(_currentPage);
setState(() {
_currentPage++;
_posts.addAll(result['posts']);
_hasMore = result['nextPageUrl'] != null;
});
} catch (e) {
throw Exception(e.toString());
} finally {
setState(() {
_isLoading = false;
});
}
}
-
_loadPosts
: Mengambil post dari API, menambahkannya ke list _posts
, dan mengatur status loading.
-
_loadMorePosts
: Mirip dengan _loadPosts
, tapi hanya dipanggil ketika user scroll ke bawah.
build
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: _buildPostList(),
floatingActionButton: FloatingActionButton(
onPressed: () {
//TODO action to add and edit post
},
child: const Icon(Icons.add),
),
);
}
-
build
: Membuat UI dengan AppBar
, ListView
untuk menampilkan post, dan FloatingActionButton
untuk menambah atau mengedit post.
_buildPostList
Widget _buildPostList() {
return ListView.builder(
controller: _scrollController,
itemCount: _posts.length + (_hasMore ? 1 : 0),
itemBuilder: (context, index) {
if (index == _posts.length) {
return const Center(child: CircularProgressIndicator());
}
final post = _posts[index];
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card.filled(
clipBehavior: Clip.hardEdge,
child: InkWell(
onTap: () {
// Todo action ke detail post
},
child: Stack(
children: [
PostView(post: post),
Positioned(
top: 2,
right: 2,
child: IconButton(
onPressed: () {
// TODO action to edit post
},
icon: const Icon(Icons.edit_rounded),
),
),
Positioned(
bottom: 2,
right: 2,
child: IconButton(
onPressed: () {
//TODO action delete post
},
icon: const Icon(Icons.delete_rounded),
),
)
],
),
),
),
);
},
);
}
-
_buildPostList
: Membuat ListView
dengan item Card
untuk setiap post. Jika masih ada data yang bisa diambil (_hasMore
), tambahkan indikator loading di bagian bawah.
dispose
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
-
dispose
: Membersihkan controller ketika widget dihapus untuk menghindari kebocoran memori.
Ini adalah penjelasan tentang kode yang diberikan, yang merupakan sebuah halaman Flutter untuk menampilkan daftar post yang diambil dari API dengan fitur paginasi dan scroll infinite.
Setelah kalian sudah membuat tampilan home atau tampilan pertama sekarang kita edit pada file main.dart
dan memanggil tampilan home
, sehingga kode pada main.dart
menjadi berikut:
import 'package:flutter/material.dart';
import 'package:flutter_pemula/screen/home.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const Home(title: 'Tutorial Flutter Pemula'),
);
}
}
setelah itu kalian run pada emulator atau device kalian masing- masing sehingga tampilannya menjadi berikut:
Kesimpulan
Pada artikel kali ini kita banyak belajar hal mulai dari membuat layout untuk menampilkan post dan mengetahui apa itu StatelessWidget
dan StatefulWidget
. untuk selanjutnya kita akan belajar cara menambah data dan mengirim gambar ke rest API.
Membangun Website dan Aplikasi Android Desa Dengan Laravel, React.js dan React Native
Membangun Aplikasi dan Website News Dengan Laravel, React.js dan Android