image

01 Dec 2025

9K

35K

Membangun Fitur Pencarian di Flutter

Fitur pencarian adalah komponen esensial dalam banyak aplikasi modern, memungkinkan pengguna untuk dengan cepat menemukan informasi yang mereka butuhkan dari kumpulan data yang besar. Implementasi fitur ini di Flutter dapat dilakukan dengan berbagai cara, mulai dari yang sederhana hingga yang kompleks dengan integrasi API dan algoritma pencarian lanjutan. Artikel ini akan memandu Anda melalui proses membangun fitur pencarian dasar di aplikasi Flutter Anda, fokus pada manajemen state dan pembaruan UI.

1. Persiapan Awal Proyek

Pertama, pastikan Anda memiliki proyek Flutter yang berfungsi. Jika belum, Anda bisa membuatnya dengan perintah berikut:


flutter create flutter_search_app
cd flutter_search_app

Kemudian, buka file lib/main.dart. Untuk contoh ini, kita akan mengimplementasikan semua kode dalam file ini.

2. Model Data

Kita memerlukan model data sederhana untuk dijadikan target pencarian. Mari kita definisikan kelas Item dan beberapa data sampel yang akan kita tampilkan dan cari.


class Item {
  final int id;
  final String name;

  Item({required this.id, required this.name});
}

List allItems = [
  Item(id: 1, name: 'Apple'),
  Item(id: 2, name: 'Banana'),
  Item(id: 3, name: 'Orange'),
  Item(id: 4, name: 'Grape'),
  Item(id: 5, name: 'Strawberry'),
  Item(id: 6, name: 'Pineapple'),
  Item(id: 7, name: 'Mango'),
  Item(id: 8, name: 'Blueberry'),
  Item(id: 9, name: 'Raspberry'),
  Item(id: 10, name: 'Watermelon'),
];

3. Struktur UI Dasar

Kita akan menggunakan Scaffold dengan AppBar dan ListView.builder untuk menampilkan hasil. Kunci dari fitur pencarian adalah bagaimana AppBar dapat berubah dari judul biasa menjadi kolom pencarian (TextField) dan bagaimana ListView memperbarui itemnya berdasarkan kueri pencarian.

4. Logika Pencarian dan Manajemen State

Kita akan menggunakan StatefulWidget untuk mengelola status pencarian. State yang perlu kita kelola meliputi:

  • _isSearching: Boolean untuk menunjukkan apakah mode pencarian aktif.
  • _searchQuery: String yang menampung input pencarian pengguna.
  • _filteredItems: Daftar Item yang ditampilkan setelah difilter.
  • _searchController: TextEditingController untuk mengelola input TextField.

Fungsi utama adalah _filterItems(String query) yang akan memproses daftar allItems dan mengembalikan daftar item yang namanya cocok dengan kueri pencarian (tanpa memedulikan huruf besar/kecil).

5. Implementasi Kode Lengkap

Berikut adalah implementasi lengkap untuk file lib/main.dart, yang mencakup model data, UI, dan logika pencarian:


import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

// Model Data
class Item {
  final int id;
  final String name;

  Item({required this.id, required this.name});
}

// Data Sampel
List allItems = [
  Item(id: 1, name: 'Apple'),
  Item(id: 2, name: 'Banana'),
  Item(id: 3, name: 'Orange'),
  Item(id: 4, name: 'Grape'),
  Item(id: 5, name: 'Strawberry'),
  Item(id: 6, name: 'Pineapple'),
  Item(id: 7, name: 'Mango'),
  Item(id: 8, name: 'Blueberry'),
  Item(id: 9, name: 'Raspberry'),
  Item(id: 10, name: 'Watermelon'),
  Item(id: 11, name: 'Lemon'),
  Item(id: 12, name: 'Peach'),
  Item(id: 13, name: 'Pear'),
  Item(id: 14, name: 'Cherry'),
  Item(id: 15, name: 'Kiwi'),
];

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Search Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State createState() => _MyHomePageState();
}

class _MyHomePageState extends State {
  bool _isSearching = false;
  String _searchQuery = '';
  final TextEditingController _searchController = TextEditingController();
  List _filteredItems = [];

  @override
  void initState() {
    super.initState();
    _filteredItems = allItems; // Tampilkan semua item di awal
    // Tambahkan listener ke controller untuk memfilter setiap kali teks berubah
    _searchController.addListener(_onSearchChanged);
  }

  @override
  void dispose() {
    _searchController.removeListener(_onSearchChanged);
    _searchController.dispose();
    super.dispose();
  }

  // Dipanggil setiap kali teks di TextField berubah
  void _onSearchChanged() {
    _filterItems(_searchController.text);
  }

  // Logika untuk memfilter item berdasarkan kueri
  void _filterItems(String query) {
    setState(() {
      _searchQuery = query;
      if (query.isEmpty) {
        _filteredItems = allItems;
      } else {
        _filteredItems = allItems
            .where((item) =>
                item.name.toLowerCase().contains(query.toLowerCase()))
            .toList();
      }
    });
  }

  // Mengaktifkan mode pencarian
  void _startSearch() {
    setState(() {
      _isSearching = true;
    });
  }

  // Menonaktifkan mode pencarian dan mereset kueri
  void _stopSearch() {
    setState(() {
      _isSearching = false;
      _searchController.clear();
      _filterItems(''); // Reset filter untuk menampilkan semua item
    });
  }

  // Widget untuk TextField pencarian di AppBar
  Widget _buildSearchField() {
    return TextField(
      controller: _searchController,
      autofocus: true, // Fokuskan secara otomatis saat mode pencarian aktif
      decoration: const InputDecoration(
        hintText: 'Cari...',
        border: InputBorder.none,
        hintStyle: TextStyle(color: Colors.white70),
      ),
      style: const TextStyle(color: Colors.white, fontSize: 16.0),
      // onChanged tidak perlu diatur di sini karena kita sudah menggunakan addListener
    );
  }

  // Aksi untuk AppBar (ikon pencarian atau ikon hapus)
  List _buildAppBarActions() {
    if (_isSearching) {
      return [
        IconButton(
          icon: const Icon(Icons.clear),
          onPressed: _stopSearch,
        ),
      ];
    } else {
      return [
        IconButton(
          icon: const Icon(Icons.search),
          onPressed: _startSearch,
        ),
      ];
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: _isSearching ? _buildSearchField() : const Text('Daftar Item'),
        actions: _buildAppBarActions(),
      ),
      body: _filteredItems.isEmpty
          ? const Center(child: Text('Tidak ada item ditemukan.'))
          : ListView.builder(
              itemCount: _filteredItems.length,
              itemBuilder: (context, index) {
                return Card(
                  margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                  elevation: 2,
                  child: ListTile(
                    title: Text(_filteredItems[index].name),
                    subtitle: Text('ID: ${_filteredItems[index].id}'),
                    onTap: () {
                      // Contoh: Menampilkan SnackBar saat item diklik
                      ScaffoldMessenger.of(context).showSnackBar(
                        SnackBar(
                            content: Text('Anda memilih ${_filteredItems[index].name}')),
                      );
                    },
                  ),
                );
              },
            ),
    );
  }
}

6. Pertimbangan Lanjutan

Implementasi di atas menyediakan fondasi yang kokoh, tetapi ada beberapa area di mana Anda dapat memperluas dan mengoptimalkan fitur pencarian:

  • Debouncing Input: Untuk aplikasi dengan data yang sangat besar atau pencarian yang memakan sumber daya (misalnya, memanggil API), Anda mungkin ingin menambahkan debouncing ke input pencarian. Ini mencegah fungsi pencarian dipanggil terlalu sering, menunggu sebentar setelah pengguna berhenti mengetik sebelum memicu pencarian. Paket seperti rxdart atau implementasi manual dengan Timer dapat membantu.
  • Pencarian Asinkron: Jika data Anda berasal dari API atau database, Anda perlu mengimplementasikan pencarian secara asinkron (misalnya, menggunakan FutureBuilder, StreamBuilder, atau state management yang lebih canggih seperti Provider/BLoC/Riverpod) untuk menangani status loading, error, dan hasil.
  • Algoritma Pencarian Lebih Lanjut: Contoh ini menggunakan pencarian berbasis substring sederhana. Untuk pengalaman pengguna yang lebih baik, pertimbangkan algoritma seperti pencarian fuzzy (misalnya, menggunakan paket fuzzy) yang dapat menemukan kecocokan bahkan jika ada kesalahan ketik kecil.
  • Performa pada Dataset Besar: Untuk dataset yang sangat besar, memfilter seluruh daftar di memori mungkin tidak efisien. Pertimbangkan untuk memuat data secara paginasi atau mendelegasikan pemfilteran ke backend untuk meningkatkan performa.
  • Manajemen State Lanjutan: Untuk aplikasi yang lebih kompleks, mengelola state pencarian dengan setState mungkin menjadi rumit. Pola manajemen state seperti Provider, BLoC, atau Riverpod dapat memberikan solusi yang lebih terstruktur dan dapat diskalakan, memisahkan logika bisnis dari UI.
  • Riwayat Pencarian: Menyimpan riwayat pencarian pengguna dan menampilkannya saat TextField kosong dapat meningkatkan kegunaan.

Kesimpulan

Membangun fitur pencarian di Flutter melibatkan kombinasi UI yang responsif dan logika pemfilteran data yang efisien. Dengan memahami bagaimana mengelola state dan memperbarui UI berdasarkan input pengguna, Anda dapat menciptakan pengalaman pencarian yang kuat dan intuitif untuk aplikasi Anda. Contoh dasar ini memberikan fondasi yang kokoh, yang dapat Anda kembangkan lebih lanjut dengan fitur-fitur dan optimasi yang lebih canggih sesuai kebutuhan proyek Anda.

Related Articles

Dec 19, 2025

Flutter & Firebase Auth: Seamless Social Media Login

Flutter & Firebase Auth: Seamless Social Media Login In today's digital landscape, user authentication is a critical component of almost every application. Pro

Dec 19, 2025

Building a Widget List with Sticky

Building a Widget List with Sticky Header in Flutter Creating dynamic and engaging user interfaces is crucial for modern applications. One common UI pattern th

Dec 19, 2025

Mastering Transform Scale & Rotate Animations in Flutter

Mastering Transform Scale & Rotate Animations in Flutter Flutter's powerful animation framework allows developers to create visually stunning and highly intera