Flutter

flutter 검색창 예제

컴공 2022. 4. 9. 01:14
반응형

flutter 작업 중에 API를 통한 위치조회 서비스를 제작중에 나온 코드를 공유겸 올립니다.

import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();


}

class _MyHomePageState extends State<MyHomePage> {


  final StreamController<String> _streamSearch = StreamController<String>();
  FocusNode textFocus = FocusNode();
  final myController = TextEditingController();


  @override
  initState() {
    super.initState();
  }
  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("StreamBuilder test"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            TextField(
              controller: myController,
              keyboardType: TextInputType.text,
              focusNode: textFocus,
              onChanged: (text) {
                _streamSearch.add(text);
              },
              decoration: const InputDecoration(
                labelText: 'Input',
              ),
            ),
            Stack(
              children: [
                StreamBuilder(
                  stream: _streamSearch.stream,
                  builder: (context, snapshot) {
                    if (snapshot.hasData == true) {
                      return FutureBuilder(
                        future: fetchSearch(snapshot.data.toString()),
                        builder: (context, AsyncSnapshot snaps) {
                          if (snaps.hasData == true) {
                            return Container(
                              height: 250,
                              child: ListView.builder(
                                shrinkWrap: true,
                                itemCount: snaps.data.length,
                                itemExtent: 50, //each rows height
                                itemBuilder: (context, index) {
                                  return ListTile(
                                    onTap: () => {
                                      textFocus.unfocus(),
                                      _streamSearch.add(''),
                                      myController.text = '',
                                      print('detail : ${snaps.data[index].place} ${snaps.data[index].x} ${snaps.data[index].y}'),
                                    },
                                    // leading:
                                    //     Text('${snaps.data[index].place}'),
                                    title: Text('${snaps.data[index].place}'),
                                    trailing: const Icon(
                                      Icons.location_pin,
                                      color: Colors.blue,
                                      size: 30.0,
                                    ),
                                  );
                                },
                              ),
                              //Text('test : ${snaps.data[1].title}'),
                            );
                          } else {
                            return Container();
                          }
                        },
                      );
                    } else {
                      return Container();
                    }
                  },
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class getPostList {
  final List<Post> entries;

  getPostList(this.entries);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      padding: const EdgeInsets.all(8),
      itemCount: entries.length,
      itemBuilder: (BuildContext context, int index) {
        return Container(
          height: 50,
          child: Center(child: Text('Entry ${entries[index].place}')),
        );
      },
    );
  }
}

Future<List<Post>> fetchSearch(String name) async {
  String x = '128.5';
  String y = '36.5';

  String url =
      'https://api.fixid.kr/get_geo.php?type=addrList&addr=$name&x=$x&y=$y';
  print(url);

  final response = await http.get(Uri.parse(url));

  if (response.statusCode == 200) {
    // 만약 서버가 OK 응답을 반환하면, JSON을 파싱합니다.
    //print(json.decode(response.body));
    //return Post.fromJSON(json.decode(response.body));

    final parsed = json.decode(response.body).cast<Map<String, dynamic>>();
    return parsed.map<Post>((json) => Post.fromJson(json)).toList();
  } else {
    // 만약 응답이 OK가 아니면, 에러를 던집니다.
    throw Exception('Failed to load post');
  }
}

class Post {
  final String place;
  final String x;
  final String y;

  Post({required this.place, required this.x, required this.y});

  factory Post.fromJson(Map<String, dynamic> json) {
    return Post(place: json['place'], x: json['x'], y: json['y']);
  }
}
반응형