Flutter快速导航插件quick_nav的使用
Flutter快速导航插件quick_nav的使用
通过我们的Flutter插件,可以为您的应用添加一个优雅的消息气泡覆盖层和集成通知功能,确保在所有应用程序中提供无缝且互动的用户体验。
支持平台
Android
关于
Quick Nav 提供了一个简化的方法来轻松显示一个消息气泡。只需遵循以下简单的步骤即可增强您的应用功能和用户交互。
该插件专门设计用于Android,利用其独特的功能以出现在所有应用程序之上。此功能在iOS系统上不可用。
关键特性
- 显示聊天头覆盖层: 在所有Android应用之上显示聊天头覆盖层。
- 集成通知功能: 集成通知功能以增强用户参与度。
- 自定义选项: 可以自定义聊天头的外观和行为。
- 简易API: 简化API,方便在Flutter项目中集成。
- 创建直观的响应式UI: 适用于创建直观且响应式的用户界面。
使用方法
- 首先,在
pubspec.yaml
文件中添加包
quick_nav: ^updated_version
- 导航到
AndroidManifest.xml
文件以包含必要的权限
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
- 轻松使用插件并探索其全部潜力,查看示例项目,以便您可以轻松发现所有优势。
插件的力量
initService
该函数应首先被调用来激活插件,因为它需要特定的属性来配置气泡。
参数 | 必填 | 描述 |
---|---|---|
screenHeight |
是 | 从MediaQuery获取逻辑像素屏幕高度 |
chatHeadIcon |
否 | 若要自定义聊天头图标,请将新图标添加到android/app/src/main/res/drawable/ 文件夹,并指定图像名称(不带文件格式)。若未指定自定义图标,则插件将默认使用存储在其’drawable’资源中的Android聊天头图标。 |
notificationIcon |
否 | 同chatHeadIcon 。当未传递图标时,默认图标为插件内的 android notification icon 。 |
notificationTitle |
否 | 当关闭聊天头时,我们会显示一个包含标题和正文的通知。如果不发送任何标题,默认通知标题为App Name |
notificationBody |
否 | 同notificationTitle ,但默认通知正文为Your Service is still working |
notificationCircleHexColor |
否 | 在Android 13及以上版本中,系统会将通知图标放在圆圈内,可以通过此参数更改圆圈颜色。 但在Android 10及以下版本中,此参数用于更改通知图标 |
checkPermission
该函数检查应用是否具有显示其他应用之上的必要权限。它返回一个布尔值:
true
: 权限已授予,允许启动气泡。false
: 权限被拒绝;在这种情况下,请先使用askPermission
。
askPermission
使用此函数,您将被引导至系统设置,具体为“显示其他应用之上”部分,以授予您的应用所需的权限。
startService
此函数使您可以启动显示覆盖的服务。
参数 | 必填 | 描述 |
---|---|---|
notificationTitle |
否 | 在启动服务之前修改通知标题。如果已在initService 中指定了标题,则服务将使用该标题。 |
notificationBody |
否 | 同notificationTitle |
stopService
此函数使您可以停止服务,关闭覆盖。
clearNotificationService
此函数允许您从状态栏移除通知。
讨论
使用问题跟踪器报告错误和请求功能。欢迎提交拉取请求。
完整示例代码
import 'dart:async';
import 'dart:math';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:quick_nav/quick_nav.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
String msg = '未知';
final _quicknavPlugin = QuickNavService.I;
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
bool inTrip = false;
bool serviceStarted = true;
[@override](/user/override)
void didChangeAppLifecycleState(AppLifecycleState state) {
print(state.name);
print(inTrip.toString());
if (!inTrip) return;
switch (state) {
case AppLifecycleState.resumed:
clearNotificationService();
stopService();
break;
case AppLifecycleState.paused:
startService();
break;
default:
break;
}
}
[@override](/user/override)
void initState() {
clearNotificationService();
WidgetsBinding.instance.addObserver(this);
// 请求Android 13及以上版本的通知权限
flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
?.requestPermission();
// 初始化服务,不初始化服务无法启动
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_quicknavPlugin
.initService(
screenHeight: MediaQuery.of(context).size.height,
)
.then((value) {
serviceStarted = value ?? false;
setState(() {});
});
});
super.initState();
}
[@override](/user/override)
void didChangeMetrics() {
stopService();
super.didChangeMetrics();
}
[@override](/user/override)
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
Future<void> startService() async {
bool serviceWorks;
try {
final double navigationBar = await getNavHeight();
if (!mounted) return;
final double density = MediaQuery.of(context).devicePixelRatio;
final double screenHeight = MediaQuery.of(context).size.height;
final double screenWidth = MediaQuery.of(context).size.width * density;
print({
'screenWidth-P.P': screenWidth,
'screenHeight-L.P': screenHeight,
'density-DPR': density,
'navigationBarHeight': navigationBar,
}.toString());
serviceWorks = await _quicknavPlugin.startService() ?? false;
if (!serviceWorks) return;
} on PlatformException catch (e) {
serviceWorks = false;
print(e.message.toString());
}
if (!mounted) return;
setState(() {
msg = (serviceWorks
? "成功启动聊天头服务"
: "启动聊天头服务时出错");
});
}
Future<void> stopService() async {
bool serviceStop;
try {
serviceStop = await _quicknavPlugin.stopService() ?? false;
} on PlatformException catch (e) {
print(e.message.toString());
serviceStop = false;
}
if (!mounted) return;
setState(() {
msg = (serviceStop
? "成功停止聊天头服务"
: "停止聊天头服务时出错");
});
}
Future<void> clearNotificationService() async =>
_quicknavPlugin.clearNotificationService();
Future<double> getNavHeight() async {
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
final screenHeight = MediaQuery.of(context).size.height;
final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
final AndroidDeviceInfo androidInfo = await deviceInfoPlugin.androidInfo;
final deviceHeight = androidInfo.displayMetrics.heightPx;
final androidNavHeight = deviceHeight / devicePixelRatio - screenHeight;
return androidNavHeight;
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
useMaterial3: true,
),
home: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: const Text('Quick Nav 插件'),
),
body: SizedBox(
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('$msg\n'),
if (serviceStarted) ...[
const SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
if (!inTrip) {
final hasAPermission =
await _quicknavPlugin.checkPermission();
if (!(hasAPermission ?? true)) {
await _quicknavPlugin.askPermission();
return;
}
}
inTrip = !inTrip;
print(inTrip.toString());
setState(() {});
},
child: Text(inTrip ? '停止行程' : '开始行程'),
),
]
],
),
),
),
);
}
}
class QuickNavService {
QuickNavService._();
static QuickNavService I = QuickNavService._();
final QuickNav _quicknav = QuickNav.I;
Future<bool?> initService({
required double screenHeight,
String? chatHeadIcon,
String? notificationIcon,
String? notificationTitle,
int? notificationCircleHexColor,
String? notificationBody,
}) =>
_quicknav.initService(
screenHeight: screenHeight,
chatHeadIcon: chatHeadIcon,
notificationIcon: notificationIcon,
notificationTitle: notificationTitle,
notificationCircleHexColor: notificationCircleHexColor,
notificationBody: notificationBody,
);
Future<bool?> startService({String? notificationTitle}) =>
_quicknav.startService(
notificationTitle: notificationTitle,
);
Future<bool?> stopService() => _quicknav.stopService();
Future<bool?> checkPermission() => _quicknav.checkPermission();
Future<bool?> askPermission() => _quicknav.askPermission();
Future<bool?> clearNotificationService() =>
_quicknav.clearServiceNotification();
}
更多关于Flutter快速导航插件quick_nav的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter快速导航插件quick_nav的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用quick_nav
插件进行快速导航的代码示例。quick_nav
插件允许开发者在应用中实现快速跳转功能,通常用于实现类似“返回顶部”或快速导航到某个特定部分的功能。
首先,确保你已经在pubspec.yaml
文件中添加了quick_nav
依赖:
dependencies:
flutter:
sdk: flutter
quick_nav: ^最新版本号 # 请替换为实际最新版本号
然后,运行flutter pub get
来获取依赖。
接下来是一个简单的示例,展示如何在Flutter应用中使用quick_nav
插件:
import 'package:flutter/material.dart';
import 'package:quick_nav/quick_nav.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Quick Nav Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: QuickNavDemo(),
);
}
}
class QuickNavDemo extends StatefulWidget {
@override
_QuickNavDemoState createState() => _QuickNavDemoState();
}
class _QuickNavDemoState extends State<QuickNavDemo> {
final QuickNavController _quickNavController = QuickNavController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Quick Nav Demo'),
),
body: Column(
children: <Widget>[
QuickNavButton(
controller: _quickNavController,
targetId: 'section1',
child: IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: () => _quickNavController.scrollToTarget('section1'),
),
),
Expanded(
child: ListView.builder(
itemCount: 20,
itemBuilder: (context, index) {
String sectionId = 'section$index';
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
QuickNavTarget(
id: sectionId,
child: Text(
'Section $index',
style: TextStyle(fontSize: 20),
),
),
SizedBox(height: 20),
],
),
);
},
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () => _quickNavController.scrollToTop(),
tooltip: 'Scroll to Top',
child: Icon(Icons.arrow_upward),
),
);
}
@override
void dispose() {
_quickNavController.dispose();
super.dispose();
}
}
代码说明:
-
依赖导入:
- 导入
flutter/material.dart
和quick_nav/quick_nav.dart
。
- 导入
-
应用入口:
- 使用
MaterialApp
作为应用入口,并设置home
为QuickNavDemo
。
- 使用
-
QuickNavDemo组件:
- 创建一个
StatefulWidget
,并在其状态类中初始化QuickNavController
。 - 在
build
方法中,使用Column
布局,包含一个QuickNavButton
和一个ListView
。 QuickNavButton
用于触发快速导航到指定的targetId
。在这个例子中,我们创建了一个简单的IconButton
,当点击时,它会调用_quickNavController.scrollToTarget('section1')
。ListView
生成了20个部分,每个部分都有一个QuickNavTarget
,其id
设置为section$index
。floatingActionButton
设置为一个FloatingActionButton
,点击时会调用_quickNavController.scrollToTop()
,实现快速滚动到顶部。
- 创建一个
-
资源释放:
- 在
dispose
方法中释放QuickNavController
资源。
- 在
这个示例展示了如何使用quick_nav
插件在Flutter应用中实现快速导航功能。你可以根据需要调整代码,以适应你的具体应用场景。