Notice
Recent Posts
Recent Comments
Link
250x250
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- 블로그#구글노출#걸리는시간#돈벌기#블러그운영
- flutter#ios#앱개발#마이봇#
- 플러터#
- flutter#sqlite#chatGPT#
- 로트제악#rohto#점안안#시린눈#일본여행#일본안약#안약
- 무료벽경이미지제거#배경이미지삭제#배경이미지 없애기#배경이미지 없는 png 만들기
- flutterfire configure#파이어베이스#플러터
- flutter#채팅창@메모창#url링크#날짜추가
- 마이봇#문서챗봇#PDF#TEXT#유투브#챗봇만들기#랭체인# langchain#벡터데이터#자료검색#챗GPT#GPT4#챗지피티
- ax5#tree#grid#단계별 펼치기# depth #시트메타
- #창작#SNS#스포츠#반려동물#연애#과제#레시피#활동#건강#운세#글쓰기#비즈니스 #AI비서#챗GPT#CHATGPT
- 마이봇#chatgpt#ai#인공지능
- 마이봇#아이폰#아이폰심사#IT고시#
- 플러터#sms#mms#문자보내기
- 마이봇#API 설정
- figma#flutter#dhwise#피그마#플러터#피그마 to 플러터 #figma to flutter
- PDF검색#PDF검색챗봇#NEXTJS#스터디#스타트업#랭체이#langchain#prisma#sqlite#
- mediasaop#webrtc#미디어서버#
- 마이봇#pdf챗봇#상담챗봇#faq챗봇#chatgpt#랭체인#llm
- firebase#message#메세지#플러터#안드로이드
- 마이봇#핸드폰대체#
- 메타인지#그릿#개발자#꾸준함
- 펫버틀러#서버연동#프로필등록#로그인서버연동#이미지#동영상#업로드용 화면#앱개발#플러터#반려생활#로딩바#loading bar#
- 광동온더그린#프랜즈#가상CC#스크린골프#
- PDF#챗봇검색#서비스#GPT4#PGT3.5#GPT#랭체인#챗봇#CHATBOT#LLM#문서검색
- 로우코드#lowcode#erp#관리시스템#시트메이트#시트메타#엑셀업로드#엑셀다운로드#그리드#데이터관리#생산관리시스템#로그관리#히스토리#입력체크
- 쇼핑몰관리시스템#매입관리#시트메타#매입채널#엑셀업로드
- fcm#메세지전송#안드로이드메세지#플러터메세지전송
- 커피#그라인더#통돌이 오픈 #로스팅#드립커피#생두#원두
- 로우코드#ERP#관리시스템#상품관리#선택박스#자동화프로그램
Archives
- Today
- Total
혼자서 앱 만드는 개발자 함께하는 AI 세상
[플러터앱개발][오일스닥] 오피넷에서 주유소 가격 정보 가져와서 구글맵에 연동 하기 본문
반응형
주유소 보관앱을 만들다보니 오피넷을 통해 가격정보를 가져와서 구글맵에 보여주는 기능을 제공하기로 했다.
오피넷 API 사이트에가서 API 승인을 받아야한다.
https://www.opinet.co.kr/user/main/mainView.do
싼 주유소 찾기 오피넷
www.opinet.co.kr
구글맵관련 dependencise 설정 해야한다.
google_maps_flutter: ^2.2.1
geolocator: ^9.0.2
gridlocator: ^0.0.2
아래 처럼 구글맵을 설정하고

오피넷 데이터 가져오기 (코드값에 오피넷에서 받아온 코드값적용)

받아온 코드값을 화면에 뿌려줌

아래처럼 구글맵에 적용화면 이다.

받아온정보를 기반으로 리스트로 뿌려줌

아래 전체 소스를 참조해서 적용해보면 빠르다.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:ui';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_webview_pro/webview_flutter.dart';
import 'package:geolocator/geolocator.dart';
import 'package:getwidget/components/list_tile/gf_list_tile.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:oilstock/views/image_view.dart';
import 'package:oilstock/views/oil_home.dart';
import 'package:oilstock/views/ship_main.dart';
import 'package:oilstock/main.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:proj4dart/proj4dart.dart';
import '../widgets/map3.dart';
import '../widgets/map4.dart';
import 'package:sliding_up_panel/sliding_up_panel.dart';
import 'package:http/http.dart' as http;
import 'package:label_marker/label_marker.dart';
const String kNavigationExamplePage = '''
<!DOCTYPE html><html>
<head><title>Navigation Delegate Example</title></head>
<body>
<p>
The navigation delegate is set to block navigation to the youtube website.
</p>
<ul>
<ul><a href="https://www.youtube.com/">https://www.youtube.com/</a></ul>
<ul><a href="https://www.google.com/">https://www.google.com/</a></ul>
</ul>
</body>
</html>
''';
class OilMap extends StatefulWidget {
final token;
final user_id;
const OilMap(this.token, this.user_id, {Key? key}) : super(key: key);
@override
_WebViewExampleState createState() => _WebViewExampleState();
}
Future<Position> getCurrentLocation() async {
Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high);
return position;
}
var currPosition = null;
Future<Position> currPo = getCurrentLocation();
class _WebViewExampleState extends State<OilMap> {
late WebViewController _controller;
final double _initFabHeight = 220.0;
double _fabHeight = 500;
double _panelHeightOpen = 500;
double _panelHeightClosed = 150.0;
late Map4 map;
late GoogleMapController mapController;
late AnimationController controller;
LatLng startLocation = LatLng(37.351, 127.3385);
final StreamController _streamController = StreamController();
@override
void initState() {
super.initState();
_fabHeight = _initFabHeight;
currPo.then((value) => {
setState(() {
currPosition = value;
googleMapInit();
})
});
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.amber[900],
title: const Text('OIL STOCK'),
leading: CircleAvatar(
maxRadius: 50.0,
backgroundImage: AssetImage('assets/icon/launcher_icon_main.png')),
// This drop down menu demonstrates that Flutter widgets can be shown over the web view.
// actions: <Widget>[
// NavigationControls(_controller.future),
// SampleMenu(_controller.future),
// ],
),
// We're using a Builder here so we have a context that is below the Scaffold
// to allow calling Scaffold.of(context) so we can show a snackbar.
body: Builder(builder: (BuildContext context) {
Future<bool> _goBack(BuildContext context) async {
if (await _controller.canGoBack()) {
_controller.goBack();
return Future.value(false);
} else {
return Future.value(true);
}
}
var document = [];
return Stack(
children: <Widget>[
Center(
child: WillPopScope(
onWillPop: () => _goBack(context),
child: (currPosition != null)
? GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: CameraPosition(
target: startLocation,
zoom: 15,
),
markers: markers,
)
: Text("로딩중...."))),
SlidingUpPanel(
maxHeight: _panelHeightOpen,
minHeight: _panelHeightClosed,
parallaxEnabled: true,
parallaxOffset: .5,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(18.0),
topRight: Radius.circular(18.0)),
onPanelSlide: (double pos) => setState(() {
_fabHeight = pos * (_panelHeightOpen - _panelHeightClosed) +
_initFabHeight;
}),
panelBuilder: (sc) => _panel(sc),
),
// the fab
Positioned(
right: 20.0,
bottom: _fabHeight,
child: FloatingActionButton(
child: Icon(
Icons.gps_fixed,
color: Theme.of(context).primaryColor,
),
onPressed: () {},
backgroundColor: Colors.white,
),
),
Positioned(
top: 0,
child: ClipRRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).padding.top,
color: Colors.transparent,
)))),
//the SlidingUpPanel Title
Positioned(
right: 20.0,
width: MediaQuery.of(context).size.width - 40,
top: 20.0,
child: TextField(
textAlignVertical: TextAlignVertical.bottom,
style: const TextStyle(
color: Colors.black,
height: 0.5,
fontSize: 20.0,
letterSpacing: 0,
decoration: TextDecoration.none),
decoration: InputDecoration(
filled: true, //<-- SEE HERE
fillColor: Colors.white,
prefixIcon: Icon(
Icons.search,
color: Color.fromARGB(255, 10, 10, 10),
),
border: OutlineInputBorder(
borderSide:
BorderSide(width: 0, color: Colors.black)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide:
BorderSide(width: 0, color: Colors.black)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(width: 1, color: Colors.black),
),
))),
],
);
}),
);
}
Point pointForward = new Point(x: 0, y: 0);
//var pointSrc = Point(x: 314996.15900, y: 544938.50758);
late Point pointSrc = new Point(x: 0, y: 0);
// Use built-in projection
Projection projSrc = Projection.get('WGS84') ??
Projection.add(
'WGS84',
'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs',
);
// Find Projection by name or define it if not exists
var projDst = Projection.get('TM128') ??
Projection.add(
'TM128',
'+proj=tmerc +lat_0=38 +lon_0=128 +k=0.9999 +x_0=400000 +y_0=600000 +ellps=bessel +units=m +no_defs +towgs84=-115.80,474.99,674.11,1.16,-2.31,-1.63,6.43',
);
void googleMapInit() {
pointSrc = Point(x: currPosition.longitude, y: currPosition.latitude);
pointForward = projSrc.transform(projDst, pointSrc);
getData();
}
Future getData() async {
var url =
'http://www.opinet.co.kr/api/aroundAll.do?code=XXXXXXX&x=${pointForward.x}&y=${pointForward.y}&radius=5000&sort=1&prodcd=B027&out=json';
http.Response response = await http.get(Uri.parse(url));
var data = jsonDecode(response.body);
var list = data['RESULT'];
_streamController.add(list['OIL']);
if (mapController != null)
mapController.animateCamera(CameraUpdate.newLatLngZoom(
LatLng(currPosition.latitude, currPosition.longitude), 14));
return list;
}
Set<Marker> markers = {};
final Map<String, Marker> _markers = {};
Future<void> _onMapCreated(GoogleMapController controller) async {
mapController = controller;
final googleOffices = await getData();
_markers.clear();
for (final office in googleOffices['OIL']) {
pointSrc.x = office['GIS_X_COOR'];
pointSrc.y = office['GIS_Y_COOR'];
pointForward = projDst.transform(projSrc, pointSrc);
final marker = Marker(
markerId: MarkerId(office['OS_NM']),
icon: await BitmapDescriptor.fromAssetImage(
const ImageConfiguration(devicePixelRatio: 1),
'assets/icon/gas-station-location-icon.png'),
position: LatLng(pointForward.y, pointForward.x),
infoWindow: InfoWindow(
title: office['OS_NM'],
snippet: '가격:' + office['PRICE'].toString(),
),
onTap: () {
print(office['OS_NM']);
},
);
// markers.add(marker);
//_markers[office['OS_NM']] = marker;
markers
.addLabelMarker(LabelMarker(
label: office['OS_NM'].toString(),
icon: await BitmapDescriptor.fromAssetImage(
const ImageConfiguration(devicePixelRatio: 2.5),
'assets/icon/gas-station-location-icon.png'),
markerId: MarkerId(office['OS_NM']),
position: LatLng(pointForward.y, pointForward.x),
backgroundColor: Colors.red,
infoWindow: InfoWindow(
title: office['OS_NM'],
snippet: '가격:' + office['PRICE'].toString(),
),
))
.then((value) {
setState(() {});
});
}
}
Widget _panel(ScrollController sc) {
return MediaQuery.removePadding(
context: context,
removeTop: true,
child: ListView(
controller: sc,
children: <Widget>[
SizedBox(
height: 10.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
DropdownButton<String?>(
style: TextStyle(color: Color.fromARGB(255, 4, 4, 4)),
onChanged: (String? newValue) {
print(newValue);
setState(() {
if (mapController != null)
mapController.animateCamera(CameraUpdate.newLatLngZoom(
LatLng(
currPosition.latitude, currPosition.longitude),
14));
});
},
items: [null, 'M', 'F']
.map<DropdownMenuItem<String?>>((String? i) {
return DropdownMenuItem<String?>(
value: i,
child:
Text({'M': '반경 10KM', 'F': '반경 20KM'}[i] ?? '반경 3KM'),
);
}).toList(),
),
DropdownButton<String?>(
style: TextStyle(color: Color.fromARGB(255, 6, 6, 6)),
onChanged: (String? newValue) {
print(newValue);
setState(() {
if (mapController != null)
mapController.animateCamera(CameraUpdate.newLatLngZoom(
LatLng(
currPosition.latitude, currPosition.longitude),
14));
});
},
items: [null, 'M', 'F']
.map<DropdownMenuItem<String?>>((String? i) {
return DropdownMenuItem<String?>(
value: i,
child: Text({'M': '평가순', 'F': '거리순'}[i] ?? '가격순'),
);
}).toList(),
),
],
),
Ink(
color: Colors.white,
height: 400,
width: double.infinity,
child: StreamBuilder(
stream: _streamController.stream,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView(
children: snapshot.data.map<Widget>((document) {
return GFListTile(
color: Colors.white,
titleText: document['OS_NM'],
subTitle: Row(
children: [
SizedBox(
width: 200,
child: Text(
document['DISTANCE'].toString() + " 미터",
style: TextStyle(
fontSize: 13, color: Colors.blue)),
),
Text(
document['PRICE'].toString() + "원",
style: TextStyle(
fontSize: 15, color: Colors.red),
),
],
),
//subTitleText: document['주소'],
icon: Image.asset(
'assets/icon/gas-station-location-icon.png',
width: 30,
height: 30,
color: Colors.red));
}).toList(),
);
}
return const Text('Loading...');
},
),
),
SizedBox(
height: 36.0,
),
/*
Container(
padding: const EdgeInsets.only(left: 24.0, right: 24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Images",
style: TextStyle(
fontWeight: FontWeight.w600,
)),
SizedBox(
height: 12.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CachedNetworkImage(
imageUrl:
"https://images.fineartamerica.com/images-medium-large-5/new-pittsburgh-emmanuel-panagiotakis.jpg",
height: 120.0,
width: (MediaQuery.of(context).size.width - 48) / 2 - 2,
fit: BoxFit.cover,
),
CachedNetworkImage(
imageUrl:
"https://cdn.pixabay.com/photo/2016/08/11/23/48/pnc-park-1587285_1280.jpg",
width: (MediaQuery.of(context).size.width - 48) / 2 - 2,
height: 120.0,
fit: BoxFit.cover,
),
],
),
],
),
),
SizedBox(
height: 36.0,
),
Container(
padding: const EdgeInsets.only(left: 24.0, right: 24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("About",
style: TextStyle(
fontWeight: FontWeight.w600,
)),
SizedBox(
height: 12.0,
),
Text(
"""Pittsburgh is a city in the state of Pennsylvania in the United States, and is the county seat of Allegheny County. A population of about 302,407 (2018) residents live within the city limits, making it the 66th-largest city in the U.S. The metropolitan population of 2,324,743 is the largest in both the Ohio Valley and Appalachia, the second-largest in Pennsylvania (behind Philadelphia), and the 27th-largest in the U.S.\n\nPittsburgh is located in the southwest of the state, at the confluence of the Allegheny, Monongahela, and Ohio rivers. Pittsburgh is known both as "the Steel City" for its more than 300 steel-related businesses and as the "City of Bridges" for its 446 bridges. The city features 30 skyscrapers, two inclined railways, a pre-revolutionary fortification and the Point State Park at the confluence of the rivers. The city developed as a vital link of the Atlantic coast and Midwest, as the mineral-rich Allegheny Mountains made the area coveted by the French and British empires, Virginians, Whiskey Rebels, and Civil War raiders.\n\nAside from steel, Pittsburgh has led in manufacturing of aluminum, glass, shipbuilding, petroleum, foods, sports, transportation, computing, autos, and electronics. For part of the 20th century, Pittsburgh was behind only New York City and Chicago in corporate headquarters employment; it had the most U.S. stockholders per capita. Deindustrialization in the 1970s and 80s laid off area blue-collar workers as steel and other heavy industries declined, and thousands of downtown white-collar workers also lost jobs when several Pittsburgh-based companies moved out. The population dropped from a peak of 675,000 in 1950 to 370,000 in 1990. However, this rich industrial history left the area with renowned museums, medical centers, parks, research centers, and a diverse cultural district.\n\nAfter the deindustrialization of the mid-20th century, Pittsburgh has transformed into a hub for the health care, education, and technology industries. Pittsburgh is a leader in the health care sector as the home to large medical providers such as University of Pittsburgh Medical Center (UPMC). The area is home to 68 colleges and universities, including research and development leaders Carnegie Mellon University and the University of Pittsburgh. Google, Apple Inc., Bosch, Facebook, Uber, Nokia, Autodesk, Amazon, Microsoft and IBM are among 1,600 technology firms generating \$20.7 billion in annual Pittsburgh payrolls. The area has served as the long-time federal agency headquarters for cyber defense, software engineering, robotics, energy research and the nuclear navy. The nation's eighth-largest bank, eight Fortune 500 companies, and six of the top 300 U.S. law firms make their global headquarters in the area, while RAND Corporation (RAND), BNY Mellon, Nova, FedEx, Bayer, and the National Institute for Occupational Safety and Health (NIOSH) have regional bases that helped Pittsburgh become the sixth-best area for U.S. job growth.
""",
softWrap: true,
),
],
),
),
*/
SizedBox(
height: 24,
),
],
));
}
Widget _button(String label, IconData icon, Color color) {
return Column(
children: <Widget>[
Container(
padding: const EdgeInsets.all(16.0),
child: Icon(
icon,
color: Colors.white,
),
decoration:
BoxDecoration(color: color, shape: BoxShape.circle, boxShadow: [
BoxShadow(
color: Color.fromRGBO(0, 0, 0, 0.15),
blurRadius: 8.0,
)
]),
),
SizedBox(
height: 12.0,
),
Text(label),
],
);
}
}
728x90
반응형
'개발일지' 카테고리의 다른 글
기아 니로 2017 스마트키 저출력 잠금장치 잘 안돼서 밧데리 교체 (0) | 2023.01.10 |
---|---|
자동차 밧데리 교체 기아 니로 하이브리드 2017 (0) | 2022.12.19 |
[개발일지] 프리랜서 프로젝트 참여를 위한 구직사이트&나의 생각 (0) | 2022.12.08 |
[개발자 일상] 주말 김장담그기 좋은날 12월 추운날 김장하기 (0) | 2022.12.05 |
[개발자 일상] 자가 밧데리 교체 더 뉴 파트스 7세대 TSI (0) | 2022.12.05 |
Comments