디자인 적으로나 개발 난이도 혹은 호환성에서 가장 맘에 드는 주소검색 api
‼️
사용량에 대한 제한이 없고, 따로 키를 발급받을 필요가 없기에 유용하다.
기본 가이드는 다음 링크를 참고해주세요
Daum Postcode Service User Guide
Flutter 용 패키지로는 kopo 라는 이름으로 개발된 패키지가 있지만, 최근에 출시된 포크 버전 remedi-kopo 패키지를 사용해보았다.
터미널 창에서 아래 명령어를 실행한다.
$ flutter pub add remedi_kopo
or
pubspec.yaml
파일 dependencies
에 추가해준다.
(이후 터미널에서 flutter pub get
명령어 실행 추천)
dependencies:
remedi_kopo: ^0.0.2
사용하고자 하는 페이지에서 import
import 'package:remedi_kopo/remedi_kopo.dart';
버튼을 생성해주고, onTap
에서 아래 코드를 실행한다.
onTap: () async {
KopoModel model = await Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => RemediKopo(),
),
);
logger.i(
'${model.zonecode} / ${model.address} / ${model.buildingName}',
);
// => 13529 / 경기 성남시 분당구 판교역로 166 / 카카오 판교 아지트
},
구현해보고 실행해보면 알겠지만, 창을 띄운 상태에서 검색하지 않고 그대로 뒤로 가면 model
의 값이 Null
로 return
이 된다. 아래 코드처럼 방지해주자.
KopoModel? model = await Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => RemediKopo(),
),
);
if (model != null) {
/// model 처리
}
가장 많이 사용될 듯한 TextFormField
에 적용시켜보자!
/// Form State
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
Map<String, String> formData = {};
/// Controller
final TextEditingController _postcodeController = TextEditingController();
final TextEditingController _addressController = TextEditingController();
final TextEditingController _addressDetailController = TextEditingController();
void _searchAddress(BuildContext context) async {
KopoModel? model = await Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => RemediKopo(),
),
);
if (model != null) {
final postcode = model.zonecode ?? '';
_postcodeController.value = TextEditingValue(
text: postcode,
);
formData['postcode'] = postcode;
final address = model.address ?? '';
_addressController.value = TextEditingValue(
text: address,
);
formData['address'] = address;
final buildingName = model.buildingName ?? '';
_addressDetailController.value = TextEditingValue(
text: buildingName,
);
formData['address_detail'] = buildingName;
}
}
우편번호와 기본주소 항목은 readOnly
로 수정을 못하도록 처리
Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
controller: _postcodeController,
decoration: const InputDecoration(
hintText: '우편번호',
),
readOnly: true,
),
TextFormField(
controller: _addressController,
decoration: const InputDecoration(
hintText: '기본주소',
),
readOnly: true,
),
TextFormField(
textInputAction: TextInputAction.done,
controller: _addressDetailController,
decoration: const InputDecoration(
hintText: '상세주소 입력',
),
),
CupertinoButton(
onPressed: () => _searchAddress(context),
child: const Text('주소검색'),
)
],
),
),
전체 소스코드
GitHub
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:remedi_kopo/remedi_kopo.dart';
class KakaoAddressScreen extends StatelessWidget {
KakaoAddressScreen({super.key});
/// Form State
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
Map<String, String> formData = {};
/// Controller
final TextEditingController _postcodeController = TextEditingController();
final TextEditingController _addressController = TextEditingController();
final TextEditingController _addressDetailController =
TextEditingController();
Widget _gap() {
return const SizedBox(
height: 10,
);
}
void _searchAddress(BuildContext context) async {
KopoModel? model = await Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => RemediKopo(),
),
);
if (model != null) {
final postcode = model.zonecode ?? '';
_postcodeController.value = TextEditingValue(
text: postcode,
);
formData['postcode'] = postcode;
final address = model.address ?? '';
_addressController.value = TextEditingValue(
text: address,
);
formData['address'] = address;
final buildingName = model.buildingName ?? '';
_addressDetailController.value = TextEditingValue(
text: buildingName,
);
formData['address_detail'] = buildingName;
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Kakao 주소검색 API'),
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
controller: _postcodeController,
decoration: const InputDecoration(
hintText: '우편번호',
),
readOnly: true,
),
_gap(),
TextFormField(
controller: _addressController,
decoration: const InputDecoration(
hintText: '기본주소',
),
readOnly: true,
),
_gap(),
TextFormField(
textInputAction: TextInputAction.done,
controller: _addressDetailController,
decoration: const InputDecoration(
hintText: '상세주소 입력',
),
),
_gap(),
CupertinoButton(
onPressed: () => _searchAddress(context),
child: const Text('주소검색'),
)
],
),
),
],
),
),
);
}
}
실행결과