🔦

無料の検索機能つけてみた

2023/06/26に公開

🔦Dartの文法で検索機能をつける

Firestoreのデータを検索するときに、Algoliaなるものを使うそうですが、お金がかかるそうで無料でできないかな〜と思い検索機能を自作しました。
とはいえ、今回作った機能は、名前が完全に一致しないと使えません。

動画も作ってみた

https://www.youtube.com/watch?v=MohxxSqZSVw

Androidでビルドするとの注意

こちらのファイルを修正しないとビルドできませんでした!

android/build.gradle
buildscript {
    ext.kotlin_version = '1.7.10'
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:7.3.0'
        // START: FlutterFire Configuration
        classpath 'com.google.gms:google-services:4.3.14'// 4.3.10から4.3.14に変更
        // END: FlutterFire Configuration
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
    project.evaluationDependsOn(':app')
}

tasks.register("clean", Delete) {
    delete rootProject.buildDir
}

💽ダミーのデータを用意する

Firestoreに、usersコレクションを作成して、String型のnameフィールドを作ってください。

ソースコードはこちら

まずは検索機能のロジックを作成します。今回のポイントは、Firestoreから取得したデータをfor文を使用して、querySnapshot.docsの中身を取り出し、userNamesの中に追加します。こちらを後ほど使用します。

user_service.dart
import 'package:cloud_firestore/cloud_firestore.dart';

class UserService {
  final CollectionReference _usersCollection =
      FirebaseFirestore.instance.collection('users');

  Future<List<String>> searchUsersByName(String name) async {
    List<String> userNames = [];

    QuerySnapshot querySnapshot =
        await _usersCollection.where('name', isEqualTo: name).get();
    // for文を使用して、querySnapshot.docsの中身を取り出す
    for (var doc in querySnapshot.docs) {
      // data()メソッドから返されるObject型をMap<String, dynamic>型にキャスト
      var data = doc.data() as Map<String, dynamic>?;
      // if文でdataがnullでないことを確認
      if (data != null) {
        String? name = data['name'];// data['name']をString型にキャスト
        if (name != null) {// nameがnullでないことを確認
          userNames.add(name);// userNamesにnameを追加
        }
      }
    }

    return userNames;
  }
}

こちらのコードで、UIにデータを表示するのを行います。

searchというメソッドを使用して、入力フォームから値をリストに保存して、例えば、hogeと一致する名前を探してくれます。

main.dart
import 'package:flutter/material.dart';
import 'user_service.dart';

class SearchPage extends StatefulWidget {
  
  _SearchPageState createState() => _SearchPageState();
}

class _SearchPageState extends State<SearchPage> {
  // UserServiceクラスのインスタンスを生成
  final UserService userService = UserService();
  // TextEditingControllerクラスのインスタンスを生成
  final TextEditingController _searchController = TextEditingController();
  // List<String>型の変数を定義
  List<String> _userNames = [];
  // searchメソッドを定義
  void search() async {
    final names = await userService.searchUsersByName(_searchController.text);
    setState(() {
      // _userNamesにnamesを代入
      _userNames = names;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('User Search'),
      ),
      body: Column(
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              controller: _searchController,
              decoration: InputDecoration(labelText: 'Search by name'),
            ),
          ),
          ElevatedButton(
            onPressed: search,
            child: Text('Search'),
          ),
          Expanded(
            child: ListView.builder(
              itemCount: _userNames.length,// _userNamesの要素数を取得
              itemBuilder: (context, index) {// indexを使用して、要素を取り出す
                return ListTile(
                  title: Text(_userNames[index]),// _userNamesの要素を表示
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

importして、ビルドする。

main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:search_app/firebase_options.dart';
import 'package:search_app/search_page.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: SearchPage(),
    );
  }
}

最後に

以前も検索機能をDartのコードだけで作ってみましたが、やはり外部サービスを使わないと、便利な検索機能を作るのは難しいなと思いました。algoliaの記事も書けたら、公開したいなと思います。

Discussion