[Flutter] 복사 가능!GoogleMap+ 카드 매끄러운 UI 만드는 방법
이런 UI 하고 싶어요?

"카드와 기호가 결합된 UI를 만들고 싶습니다."
"그런데 아래 카드 부분은 어떻게 해요?
번뇌가 계속되는 반세기.드디어 그 방법을 찾았어...(매우 간단)
메서드

언뜻 보기에는 카드 부분은 설치하기 어렵지만 알면 간단합니다.
카드 부분PageView 실시!
Google Map에서 PageView를 Stack으로 겹치는 것일 뿐입니다.
PageView에서는 가장자리를 보는 느낌과 카드를 닦는 동작을 쉽게 구현할 수 있습니다!그다음에 교환할 때 임의의 기호로 카메라를 움직인다는 운동 연합!그럼 전선 한번 볼까요?
이루어지다
Shop 클래스 만들기
지도에 가게 정보를 표시하고 샵 등급을 만들려고 합니다.
이름과 좌표 정보를 가지고 있습니다.
class Shop {
String uid;
double latitude;
double longitude;
String name;
Shop(this.uid, this.latitude, this.longitude, this.name);
}
Shop 목록 만들기
이번엔 현지에서 샵의 리스트를 제작한다.실제로 파이어스토어와 DB에 매장 정보를 미리 등록해서 가져갈 것 같아요.이번에는 홋카이도의 명소를 적절히 설정했다
final shops = [
Shop('1', 43.0779575, 141.337819, '北海道大学'),
Shop('2', 43.0692162, 141.3473406, '175°DENO坦々麺札幌駅北口店'),
Shop('3', 43.05432, 141.3517185, 'UTAGE SAPPORO'),
Shop('4', 43.0673817, 141.3416878, 'ラーメン二郎札幌店'),
Shop('5', 43.072069, 141.331253, '焼肉と料理シルクロード'),
];
Map 섹션
나는 마크스의 부분이 중요해질 것이라고 생각한다.아까 List
또 표지판을 클릭할 때 아래 카드에 가볍게 두드린 가게를 표시할 수 있다.
Widget _mapSection() {
return GoogleMap(
mapType: MapType.normal,
initialCameraPosition: _initialCameraPosition,
onMapCreated: (GoogleMapController controller) {
_mapController = controller;
},
markers: shops.map(
(selectedShop) {
return Marker(
markerId: MarkerId(selectedShop.uid),
position: LatLng(selectedShop.latitude, selectedShop.longitude),
icon: BitmapDescriptor.defaultMarker,
onTap: () async {
//タップしたマーカー(shop)のindexを取得
final index = shops.indexWhere((shop) => shop == selectedShop);
//タップしたお店がPageViewで表示されるように飛ばす
_pageController.jumpToPage(index);
},
);
},
).toSet(),
);
}
카드(PageView) 섹션
아래 카드 섹션을 PageView로 표시합니다.
또
onPageChanged
교환 후 List<shop>
의index를 얻었다.패지뷰를 통해 교환 후 중간에 나타나는 샵을 알 수 있다는 것이다.그리고 Google Map Controller로 카메라를 그 좌표까지 이동합니다! Widget _cardSection() {
return Container(
height: 148,
padding: const EdgeInsets.fromLTRB(0, 0, 0, 20),
child: PageView(
onPageChanged: (int index) async {
//スワイプ後のページのお店を取得
final selectedShop = shops.elementAt(index);
//現在のズームレベルを取得
final zoomLevel = await _mapController.getZoomLevel();
//スワイプ後のお店の座標までカメラを移動
_mapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(selectedShop.latitude, selectedShop.longitude),
zoom: zoomLevel,
),
),
);
},
controller: _pageController,
children: _shopTiles(),
),
);
}
//カード1枚1枚について
List<Widget> _shopTiles() {
final _shopTiles = shops.map(
(shop) {
return Card(
child: SizedBox(
height: 100,
child: Center(
child: Text(shop.name),
),
),
);
},
).toList();
return _shopTiles;
}
지도와 카드를 겹치다
각각 Stack으로 중첩됩니다.
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.bottomCenter,
children: [
_mapSection(),
_cardSection(),
],
);
}
복사 붙여넣기 ok!전체 텍스트 샘플 코드
main.dart
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Google Maps Demo',
home: MapSample(),
);
}
}
class MapSample extends StatefulWidget {
const MapSample({Key? key}) : super(key: key);
State<MapSample> createState() => MapSampleState();
}
class MapSampleState extends State<MapSample> {
late GoogleMapController _mapController;
final _pageController = PageController(
viewportFraction: 0.85,//0.85くらいで端っこに別のカードが見えてる感じになる
);
//初期位置を札幌駅に設定してます
final CameraPosition _initialCameraPosition = const CameraPosition(
target: LatLng(43.0686606, 141.3485613),
zoom: 12,
);
void initState() {
super.initState();
}
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.bottomCenter,
children: [
_mapSection(),
_cardSection(),
],
);
}
Widget _mapSection() {
return GoogleMap(
mapType: MapType.normal,
initialCameraPosition: _initialCameraPosition,
onMapCreated: (GoogleMapController controller) {
_mapController = controller;
},
markers: shops.map(
(selectedShop) {
return Marker(
markerId: MarkerId(selectedShop.uid),
position: LatLng(selectedShop.latitude, selectedShop.longitude),
icon: BitmapDescriptor.defaultMarker,
onTap: () async {
//タップしたマーカー(shop)のindexを取得
final index = shops.indexWhere((shop) => shop == selectedShop);
//タップしたお店がPageViewで表示されるように飛ばす
_pageController.jumpToPage(index);
},
);
},
).toSet(),
);
}
Widget _cardSection() {
return Container(
height: 148,
padding: const EdgeInsets.fromLTRB(0, 0, 0, 20),
child: PageView(
onPageChanged: (int index) async {
//スワイプ後のページのお店を取得
final selectedShop = shops.elementAt(index);
//現在のズームレベルを取得
final zoomLevel = await _mapController.getZoomLevel();
//スワイプ後のお店の座標までカメラを移動
_mapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(selectedShop.latitude, selectedShop.longitude),
zoom: zoomLevel,
),
),
);
},
controller: _pageController,
children: _shopTiles(),
),
);
}
List<Widget> _shopTiles() {
final _shopTiles = shops.map(
(shop) {
return Card(
child: SizedBox(
height: 100,
child: Center(
child: Text(shop.name),
),
),
);
},
).toList();
return _shopTiles;
}
}
/// お店の情報を持つクラス。マップに表示させるために座標を持たせている
class Shop {
String uid;
double latitude;
double longitude;
String name;
Shop(this.uid, this.latitude, this.longitude, this.name);
}
/// 北海道の名所
final shops = [
Shop('1', 43.0779575, 141.337819, '北海道大学'),
Shop('2', 43.0692162, 141.3473406, '175°DENO坦々麺札幌駅北口店'),
Shop('3', 43.05432, 141.3517185, 'UTAGE SAPPORO'),
Shop('4', 43.0673817, 141.3416878, 'ラーメン二郎札幌店'),
Shop('5', 43.072069, 141.331253, '焼肉と料理シルクロード'),
];
총결산
어때요?개인적으로 Widget 사용법을 알면 그렇게 어렵지 않을 거라고 생각해요!Fulutter의 UI 제작에서 Widget의 지식은 매우 중요합니다. 모르면 큰 차이가 있을 수 있다는 것을 알기 때문에 모든 Widget를 간단하게 접촉하는 것이 좋습니다!
Reference
이 문제에 관하여([Flutter] 복사 가능!GoogleMap+ 카드 매끄러운 UI 만드는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/wakanao/articles/bc50ca942eb450텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)