Flutter导航管理插件nb_navigation_flutter的使用
Flutter导航管理插件nb_navigation_flutter的使用
简介
Nextbillion Navigation Flutter 是一个用于Flutter应用的地图和导航功能的插件。它提供了地图显示、路线规划、导航等功能,支持Android和iOS平台。本文将详细介绍如何使用该插件,并提供一个完整的示例demo。
前提条件
- Access Key:需要一个有效的Access Key来初始化插件。
- Android minSdkVersion 17+
- iOS 11+
- Flutter 3.10+
- Pod 1.11.3+
- 确保在构建设置中将“Build Libraries for Distribution”设置为No。
安装
依赖项
在pubspec.yaml
文件中添加以下依赖项:
dependencies:
nb_navigation_flutter: {version}
导入
在代码中导入导航插件:
import 'package:nb_navigation_flutter/nb_navigation_flutter.dart';
初始化
在应用启动时初始化插件:
import 'package:nb_navigation_flutter/nb_navigation_flutter.dart';
class _NavigationDemoState extends State<NavigationDemo> {
[@override](/user/override)
void initState() {
super.initState();
NextBillion.initNextBillion(YOUR_ACCESS_KEY);
}
}
必需的权限
Android
在AndroidManifest.xml
中添加以下权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
iOS
在Runner/Info.plist
中添加以下键值对:
<key>NSLocationWhenInUseUsageDescription</key>
<string>[您的解释]</string>
观察和跟踪用户位置
为了跟踪用户位置,您需要添加回调函数并在地图加载完成后动画化相机到用户位置。
void _onMapCreated(NextbillionMapController controller) {
this.controller = controller;
}
_onUserLocationUpdate(UserLocation location) {
currentLocation = location;
}
_onStyleLoadedCallback() {
if (currentLocation != null) {
controller?.animateCamera(
CameraUpdate.newLatLngZoom(currentLocation!.position, 14),
duration: Duration(milliseconds: 400),
);
}
}
NBMap(
onMapCreated: _onMapCreated,
onStyleLoadedCallback: _onStyleLoadedCallback,
initialCameraPosition: const CameraPosition(
target: LatLng(0, 0),
zoom: 14.0,
),
trackCameraPosition: true,
myLocationEnabled: true,
myLocationTrackingMode: MyLocationTrackingMode.Tracking,
onUserLocationUpdated: _onUserLocationUpdate,
)
使用
NB Maps
如果您需要使用地图相关功能(例如显示地图小部件),请参考Flutter Maps Plugin。
获取路线
您可以使用RouteRequestParams
请求路线:
RouteRequestParams requestParams = RouteRequestParams(
origin: origin,
destination: dest,
// waypoints: [waypoint1, waypoint2],
// language: 'en',
// alternatives: true,
// overview: ValidOverview.simplified,
// avoid: [SupportedAvoid.toll, SupportedAvoid.ferry],
// option: SupportedOption.flexible,
// unit: SupportedUnits.imperial,
// mode: ValidModes.car,
// geometry: SupportedGeometry.polyline,
);
DirectionsRouteResponse routeResponse = await NBNavigation.fetchRoute(requestParams);
绘制路线
获取路线后,可以在地图上绘制路线:
void _onMapCreated(NextbillionMapController controller) {
this.controller = controller;
}
void _onStyleLoaded() {
if (controller != null) async {
navNextBillionMap = await NavNextBillionMap.create(controller!);
}
}
navNextBillionMap.drawRoute(routes);
拟合地图相机到路线点
void fitCameraToBounds(List<DirectionsRoute> routes) {
List<LatLng> multiPoints = [];
for (var route in routes) {
var routePoints = decode(route.geometry ?? '', _getDecodePrecision(route.routeOptions));
multiPoints.addAll(routePoints);
}
if (multiPoints.isNotEmpty) {
var latLngBounds = LatLngBounds.fromMultiLatLng(multiPoints);
controller?.animateCamera(
CameraUpdate.newLatLngBounds(latLngBounds, top: 50, left: 50, right: 50, bottom: 50),
);
}
}
int _getDecodePrecision(RouteRequestParams? routeOptions) {
return routeOptions?.geometry == SupportedGeometry.polyline ? PRECISION : PRECISION_6;
}
清除路线
navNextBillionMap.clearRoute();
切换替代路线可见性
navNextBillionMap.toggleAlternativeVisibilityWith(visible);
切换路线持续时间符号可见性
navNextBillionMap.toggleDurationSymbolVisibilityWith(visible);
添加路线选择监听器
onMapClick(Point<double> point, LatLng coordinates) {
navNextBillionMap.addRouteSelectedListener(coordinates, (selectedRouteIndex) {});
}
开始导航
使用NavigationLauncherConfig
开始导航:
NavigationLauncherConfig config = NavigationLauncherConfig(
route: routes.first,
routes: routes,
shouldSimulateRoute: true,
);
NBNavigation.startNavigation(config);
启动嵌入式NavigationView
NBNavigationView
是一个可自定义的导航视图小部件,提供无缝的导航体验。
注意事项
如果您想使用NavigationView,需要在Android项目中将MainActivity
继承自FlutterFragmentActivity
而不是FlutterActivity
:
class MainActivity: FlutterFragmentActivity() {
}
NBNavigationView构造函数
const NBNavigationView({
super.key,
required this.navigationOptions,
this.onNavigationViewReady,
this.onProgressChange,
this.onNavigationCancelling,
this.onArriveAtWaypoint,
this.onRerouteFromLocation,
});
参数
navigationOptions
(必需):提供导航视图的必要配置。onNavigationViewReady
:当导航视图准备好时触发的回调。onProgressChange
:当导航进度发生变化时触发的回调。onNavigationCancelling
:当导航被取消时触发的回调。onArriveAtWaypoint
:当到达某个路点时触发的回调。onRerouteFromLocation
:当从某个位置重新规划路线时触发的回调。
示例用法
NBNavigationView(
navigationOptions: NavigationLauncherConfig(
route: selectedRoute,
routes: allRoutes,
themeMode: NavigationThemeMode.system,
),
onNavigationViewReady: (controller) {
// 处理导航视图准备好的事件
},
onProgressChange: (progress) {
// 处理导航进度变化的事件
},
onNavigationCancelling: () {
// 处理导航取消的事件
},
onArriveAtWaypoint: (waypoint) {
// 处理到达路点的事件
},
onRerouteFromLocation: (location) {
// 处理从某个位置重新规划路线的事件
},
);
UI组件
您可以自定义NavigationView的样式。
Android
在styles.xml
中添加自定义样式:
<style name="CustomNavigationViewLight" parent="NavigationViewLight">
<!-- 自定义导航样式 -->
<item name="navViewBannerBackground">@color/color</item>
<item name="navViewBannerPrimaryText">@color/color</item>
...
</style>
<style name="CustomNavigationViewDark" parent="NavigationViewDark">
<item name="navViewBannerBackground">@color/colorAccent</item>
</style>
iOS
在AppDelegate.swift
中导入nb_navigation_flutter
并自定义NavigationView样式:
import nb_navigation_flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
customStyle()
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func customStyle() {
NavStyleManager.customDayStyle = CustomDayStyle()
NavStyleManager.customNightStyle = CustomNightStyle()
}
}
import NbmapNavigation
class CustomDayStyle: DayStyle {
required init() {
super.init()
}
override func apply() {
super.apply()
ArrivalTimeLabel.appearance().font = UIFont.systemFont(ofSize: 18, weight: .medium).adjustedFont
ArrivalTimeLabel.appearance().normalTextColor = #color
BottomBannerContentView.appearance().backgroundColor = #color
}
}
class CustomNightStyle: NightStyle {
required init() {
super.init()
}
override func apply() {
super.apply()
NavigationMapView.appearance().trafficUnknownColor = UIColor.green
}
}
运行示例代码
请参考示例代码。
完整示例Demo
以下是一个完整的示例demo,展示了如何使用nb_navigation_flutter
插件进行导航管理:
import 'package:flutter/material.dart';
import 'package:nb_navigation_flutter/nb_navigation_flutter.dart';
import 'package:permission_handler/permission_handler.dart';
final Map<String, Widget> _allPages = <String, Widget>{
'Full Navigation Example': const FullNavigationExample(),
'Launch Embedded Navigation View': const LaunchEmbeddedNavigationView(),
'Custom View On Navigation View': const CustomViewOnNavigationView(),
'Launch Navigation': const LaunchNavigation(),
'Draw Route Line': const DrawRouteLine(),
'Draw Route Line With Raw JSON': const DrawRouteLineWithRawJson(),
'Track Current Location': const TrackCurrentLocation(),
'Route Line Style': const RouteLineStyle(),
'Custom Navigation Style': const CustomNavigationStyle(),
'Map View Style': const MapViewStyle(),
'Navigation Theme': const NavigationTheme(),
'Embedded Navigation View Integration': const EmbeddedNavigationViewIntegration(),
};
class NavigationDemo extends StatefulWidget {
static const String accessKey = String.fromEnvironment("ACCESS_KEY");
const NavigationDemo({super.key});
[@override](/user/override)
State<NavigationDemo> createState() => _NavigationDemoState();
}
class _NavigationDemoState extends State<NavigationDemo> {
[@override](/user/override)
void initState() {
super.initState();
NBNavigation.initNextBillion(NavigationDemo.accessKey);
// Set user ID If needed
NBNavigation.setUserId("123344").then((value) {});
// Check user ID If needed
NBNavigation.getUserId().then((value) {});
// Get NB ID If needed
NBNavigation.getNBId().then((value) {});
}
void _pushPage(BuildContext context, Widget page, bool isRequiredPermission) async {
if (!mounted) {
return;
}
if (isRequiredPermission) {
var status = await Permission.location.status;
if (!mounted) {
return;
}
if (status.isDenied) {
await [Permission.location].request();
if (!mounted) {
return;
}
}
}
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Builder(
builder: (newContext) => page,
),
),
);
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('NBNavigation examples')),
body: NavigationDemo.accessKey.isEmpty
? buildAccessTokenWarning()
: ListView.separated(
itemCount: _allPages.length,
separatorBuilder: (BuildContext context, int index) => const Divider(height: 1),
itemBuilder: (_, int index) => ListTile(
title: Text(_allPages.keys.toList()[index]),
onTap: () {
_pushPage(context, _allPages.values.toList()[index], true);
},
),
),
);
}
Widget buildAccessTokenWarning() {
return Container(
color: Colors.red[900],
child: SizedBox.expand(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
"Using MapView requires calling Nextbillion.initNextbillion(String accessKey) "
"before inflating or creating NBMap Widget. ",
]
.map((text) => Padding(
padding: const EdgeInsets.all(8),
child: Text(text,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white)),
))
.toList(),
),
),
);
}
}
void main() {
runApp(const MaterialApp(home: NavigationDemo()));
}
更多关于Flutter导航管理插件nb_navigation_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter导航管理插件nb_navigation_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何使用nb_navigation_flutter
插件进行Flutter导航管理的代码案例。nb_navigation_flutter
是一个用于简化Flutter应用中的导航管理的插件。
首先,确保你已经在pubspec.yaml
文件中添加了nb_navigation_flutter
依赖:
dependencies:
flutter:
sdk: flutter
nb_navigation_flutter: ^最新版本号 # 请替换为最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,让我们看一下如何在Flutter应用中使用nb_navigation_flutter
进行导航管理。
1. 设置导航服务
在你的应用入口文件(通常是main.dart
)中,设置导航服务:
import 'package:flutter/material.dart';
import 'package:nb_navigation_flutter/nb_navigation_flutter.dart';
import 'routes.dart'; // 假设你有一个routes.dart文件来定义路由
void main() {
// 初始化导航服务
final navService = NavigationService();
// 注册路由
navService.registerRoutes(routes);
runApp(
MaterialApp.router(
routeInformationParser: navService.routeInformationParser,
routerDelegate: navService.routerDelegate,
),
);
}
2. 定义路由
在routes.dart
文件中定义你的路由:
import 'package:nb_navigation_flutter/nb_navigation_flutter.dart';
import 'home_screen.dart';
import 'details_screen.dart';
final routes = <String, WidgetBuilder>{
'/': (context) => HomeScreen(),
'/details': (context) => DetailsScreen(),
};
3. 创建屏幕
创建两个简单的屏幕:home_screen.dart
和details_screen.dart
。
home_screen.dart
:
import 'package:flutter/material.dart';
import 'package:nb_navigation_flutter/nb_navigation_flutter.dart';
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final navService = NavigationService.of(context);
return Scaffold(
appBar: AppBar(
title: Text('Home Screen'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
navService.navigateTo('/details');
},
child: Text('Go to Details'),
),
),
);
}
}
details_screen.dart
:
import 'package:flutter/material.dart';
import 'package:nb_navigation_flutter/nb_navigation_flutter.dart';
class DetailsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final navService = NavigationService.of(context);
return Scaffold(
appBar: AppBar(
title: Text('Details Screen'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
navService.navigateBack();
},
child: Text('Go Back'),
),
),
);
}
}
4. 使用导航服务
在上面的代码中,我们使用了NavigationService.of(context)
来获取导航服务的实例,并通过navigateTo
和navigateBack
方法来进行导航。
注意事项
- 确保你已经正确导入了
nb_navigation_flutter
包。 NavigationService.of(context)
需要在MaterialApp.router
的上下文中使用。- 路由的路径和WidgetBuilder需要正确匹配。
这样,你就完成了使用nb_navigation_flutter
插件进行Flutter导航管理的基本设置。这个插件使得管理复杂的导航变得更加简单和直观。