Flutter引导高亮插件highlighter_coachmark的使用
Flutter引导高亮插件highlighter_coachmark的使用
在用户引导过程中,有多种方式可以向用户展示功能。例如,通过截图展示、叠加方向箭头、Material Design风格的功能发现或教练标记(Coach Mark)。这个教练标记插件会在背景模糊的同时突出显示所需元素。
该插件的特点是它会创建一个模糊的背景,并高亮显示目标元素。以下是一张动图,展示了它的效果:
此外,根据用户体验设计的建议:
- 一次只展示一个提示,且在适当的时间展示,这样用户更容易理解和学习指令。
- 教练标记应专注于创新或令人意想不到的功能。
使用方法
查看示例文件夹中的代码。那里有四个教练标记示例,它们都展示在上面的GIF中。
示例代码
// 初始化教练标记对象
CoachMark coachMark = CoachMark();
// 获取目标元素的上下文和矩形区域
RenderBox target = targetGlobalKey.currentContext.findRenderObject();
Rect markRect = target.localToGlobal(Offset.zero) & target.size;
markRect = Rect.fromCircle(center: markRect.center, radius: markRect.longestSide * 0.6);
// 显示教练标记
coachMark.show(
targetContext: targetGlobalKey.currentContext, // 目标上下文
markRect: markRect, // 高亮区域
children: [
Positioned(
top: markRect.top + 5.0,
right: 10.0,
child: Text("长按按钮以查看更多选项",
style: const TextStyle(
fontSize: 24.0,
fontStyle: FontStyle.italic,
color: Colors.white,
)))
],
duration: null, // 持续时间,为null表示无限时长
onClose: () {
appState.setCoachMarkIsShown(true); // 关闭回调
});
类似插件
- super_tooltip - 在覆盖层上添加带有箭头的提示框。
- feature-discovery - 按照Material Design指南实现的功能发现。
感谢
- Simon Lightfoot - 帮助实现高亮区域的柔和边缘。
- Thomas Burkhart - 提供了发布其插件的灵感,并采用了Overlay模式。
- Iiro Krankka - 使用了他的FlutterMates 项目作为示例。
完整示例代码
以下是一个完整的示例代码,展示了如何使用 highlighter_coachmark
插件。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:highlighter_coachmark/highlighter_coachmark.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: const Color(0xFFF850DD),
),
home: FriendsListPage(),
);
}
}
class FriendsListPage extends StatefulWidget {
[@override](/user/override)
_FriendsListPageState createState() => _FriendsListPageState();
}
class _FriendsListPageState extends State<FriendsListPage> {
List<Friend> _friends = [];
ScrollController _scrollController;
GlobalKey _fabKey = GlobalObjectKey("fab");
GlobalKey _tileKey = GlobalObjectKey("tile_2");
[@override](/user/override)
void initState() {
super.initState();
_scrollController = ScrollController();
_loadFriends();
}
Future<void> _loadFriends() async {
http.Response response = await http.get('https://randomuser.me/api/?results=5');
setState(() {
_friends = Friend.allFromResponse(response.body);
});
// 启动教练标记教程
Timer(Duration(seconds: 1), () => showCoachMarkFAB());
}
// 显示第一个教练标记
void showCoachMarkFAB() {
CoachMark coachMarkFAB = CoachMark();
RenderBox target = _fabKey.currentContext.findRenderObject();
Rect markRect = target.localToGlobal(Offset.zero) & target.size;
markRect = Rect.fromCircle(
center: markRect.center, radius: markRect.longestSide * 0.6);
coachMarkFAB.show(
targetContext: _fabKey.currentContext,
markRect: markRect,
children: [
Center(
child: Text("点击按钮\n添加朋友",
style: const TextStyle(
fontSize: 24.0,
fontStyle: FontStyle.italic,
color: Colors.white,
)))
],
duration: null,
onClose: () {
Timer(Duration(seconds: 3), () => showCoachMarkTile());
});
}
// 显示第二个教练标记
void showCoachMarkTile() {
CoachMark coachMarkTile = CoachMark();
RenderBox target = _tileKey.currentContext.findRenderObject();
Rect markRect = target.localToGlobal(Offset.zero) & target.size;
markRect = markRect.inflate(5.0);
coachMarkTile.show(
targetContext: _fabKey.currentContext,
markRect: markRect,
markShape: BoxShape.rectangle,
children: [
Positioned(
top: markRect.bottom + 15.0,
right: 5.0,
child: Text("点击朋友查看详情",
style: const TextStyle(
fontSize: 24.0,
fontStyle: FontStyle.italic,
color: Colors.white,
)))
],
duration: Duration(seconds: 3));
}
[@override](/user/override)
Widget build(BuildContext context) {
Widget content;
if (_friends.isEmpty) {
content = Center(
child: CircularProgressIndicator(),
);
} else {
content = ListView.builder(
itemExtent: 70.0,
controller: _scrollController,
itemCount: _friends.length,
itemBuilder: _buildFriendListTile,
);
}
return Scaffold(
appBar: AppBar(title: Text('朋友们')),
body: content,
floatingActionButton: _friends.isEmpty
? null
: FloatingActionButton(
key: _fabKey,
child: Icon(Icons.add),
onPressed: () async {
Friend friend = await buildShowDialog(context);
if (friend != null) {
setState(() {
_friends.add(friend);
});
Future.delayed(
Duration(milliseconds: 200),
() => _scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: Duration(seconds: 1),
curve: Curves.easeOut));
}
},
),
);
}
Widget _buildFriendListTile(BuildContext context, int index) {
var friend = _friends[index];
GlobalKey key = index == 2 ? _tileKey : null;
return ListTile(
key: key,
onTap: () => _navigateToFriendDetails(friend, index),
leading: Hero(
tag: index,
child: CircleAvatar(
backgroundImage: NetworkImage(friend.avatar),
),
),
title: Text(friend.name),
subtitle: Text(friend.email),
);
}
void _navigateToFriendDetails(Friend friend, Object avatarTag) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (c) {
return FriendDetailsPage(friend, avatarTag: avatarTag);
},
),
);
}
Future<Friend> buildShowDialog(BuildContext context) {
return showDialog<Friend>(
context: context,
builder: (BuildContext context) {
return FutureBuilder<Friend>(
future: _loadRandomFriend(),
builder: (BuildContext context, AsyncSnapshot<Friend> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return SimpleDialog(
title: _buildDialogAddFriend(snapshot.data));
} else {
return SimpleDialog(
title: Container(
height: 100.0,
width: 200.0,
alignment: Alignment.center,
color: Colors.white,
child: CircularProgressIndicator()));
}
});
});
}
Future<Friend> _loadRandomFriend() async {
http.Response response = await http.get('https://randomuser.me/api/?results=1');
var friends = Friend.allFromResponse(response.body);
return friends.first;
}
Widget _buildDialogAddFriend(Friend friend) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(friend.avatar),
),
title: Text(friend.name),
subtitle: Text(friend.email),
),
Padding(
padding: EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SimpleDialogOption(
onPressed: () {
Navigator.pop(context);
},
child: const Text('取消'),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, friend);
},
child: const Text('保存'),
),
],
)),
],
);
}
}
class Friend {
final String name;
final String email;
final String avatar;
Friend({this.name, this.email, this.avatar});
static List<Friend> allFromResponse(String responseBody) {
// 解析JSON数据并返回Friend列表
// 这里省略具体实现
return [];
}
}
更多关于Flutter引导高亮插件highlighter_coachmark的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter引导高亮插件highlighter_coachmark的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
highlighter_coachmark
是一个用于在 Flutter 应用中创建引导高亮效果的插件。它可以帮助你突出显示应用中的特定部件,并显示引导信息,以帮助用户更好地理解应用的功能。
安装
首先,你需要在 pubspec.yaml
文件中添加 highlighter_coachmark
依赖:
dependencies:
flutter:
sdk: flutter
highlighter_coachmark: ^1.0.0 # 请检查最新版本
然后运行 flutter pub get
来安装依赖。
基本用法
-
导入包:
import 'package:highlighter_coachmark/highlighter_coachmark.dart';
-
创建高亮引导:
你可以使用
Coachmark
类来创建一个高亮引导。通常,你需要在Widget
的build
方法中使用它。class MyHomePage extends StatelessWidget { final GlobalKey _buttonKey = GlobalKey(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Highlighter Coachmark Example'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ ElevatedButton( key: _buttonKey, onPressed: () { // 显示引导高亮 Coachmark( target: _buttonKey, text: 'This is a button. Tap it to perform an action.', onClose: () { print('Coachmark closed'); }, ).show(context); }, child: Text('Show Coachmark'), ), ], ), ), ); } }
-
配置引导高亮:
Coachmark
类提供了多个配置选项,例如:target
: 需要高亮的部件的GlobalKey
。text
: 显示的引导文本。onClose
: 引导关闭时的回调函数。shape
: 高亮的形状(例如圆形、矩形等)。padding
: 高亮区域的内边距。color
: 高亮的背景颜色。textStyle
: 引导文本的样式。
例如:
Coachmark( target: _buttonKey, text: 'This is a button. Tap it to perform an action.', shape: ShapeLightFocus.RRect, padding: 10, color: Colors.blue.withOpacity(0.5), textStyle: TextStyle(color: Colors.white, fontSize: 16), onClose: () { print('Coachmark closed'); }, ).show(context);
高级用法
你可以通过组合多个 Coachmark
来创建复杂的引导流程。例如,你可以在用户完成一个引导后,自动显示下一个引导。
void showCoachmarkSequence(BuildContext context) {
Coachmark(
target: _buttonKey1,
text: 'This is the first button.',
onClose: () {
Coachmark(
target: _buttonKey2,
text: 'This is the second button.',
onClose: () {
Coachmark(
target: _buttonKey3,
text: 'This is the third button.',
).show(context);
},
).show(context);
},
).show(context);
}