Features Tour 是一個 Flutter 套件,專門協助開發者建立逐步介紹應用程式功能的引導教學。它讓使用者能透過可自訂的提示氣泡、箭頭與動畫,突出顯示特定元件,以結構化的方式引導使用者了解關鍵功能。非常適合用於新使用者入門或展示進階功能,支援 Android、iOS、Web、macOS、Windows 與 Linux 等多個平台。此套件輕量且能順暢整合至現有的 Flutter 專案中。
適用情境
引導新使用者
突出顯示應用功能
引導式教程
用戶教育
功能示範
主要特色
逐步遊覽導航
可自訂的工具提示和強調
對多個平台的支援
流暢的動畫
與現有小部件的輕鬆整合
可設定的參觀流程
適合對象
應用入門畫面
教育類應用程式
產品示範
新功能介紹
用戶參與工具
使用建議
可能需要額外的樣式來處理複雜的使用者介面
旅遊順序必須預先定義
大量步驟帶來的效能影響
有限的內建分析功能
不適用於沒有自定義邏輯的動態內容
原始 README
以下為關聯原始碼儲存庫的 README 原文快照,最新內容請造訪原始碼儲存庫。
Features Tour
Features Tour is a package that enables you to easily create tours to introduce your widget features in your app with order. It provides a straightforward and flexible API that allows you to customize the look and feel of the tour to match your app's design.
final tourController = FeaturesTourController<HomeTourStep>('HomePage');
Use a stable page name. The controller persists tour progress by page, so changing the name will make the tour look new again.
Wrap a feature
Prefer enum-based steps. The enum declaration order becomes the tour order, and the step name becomes the cache key.
enumHomeTourStep {
drawer,
drawerButton,
settings,
list,
firstItem,
lastItem,
dialogButton,
restart,
addButton,
}
FeaturesTour<HomeTourStep>(
controller: tourController,
step: HomeTourStep.drawer,
nextStep: HomeTourStep.drawerButton,
introduce: constText('Tap here to open the drawer'),
onAfterAction: (action) {
if (action caseTourAction.next || TourAction.done) {
scaffoldKey.currentState?.openDrawer();
}
},
child: IconButton(
icon: constIcon(Icons.menu),
onPressed: () => scaffoldKey.currentState?.openDrawer(),
),
)
Use onBeforeAction to prepare the current surface, for example by scrolling a widget into view. Use onAfterAction when the current step should open a drawer, dialog, or another surface before the next step appears.
firstStep is the preferred entry point. The controller still accepts firstIndex and firstIndexTimeout for migration, but new code should use the enum-based API.
Instantiate the controller and widgets with the same enum type so step, nextStep, and firstStep stay type-safe.
Global Configuration
Set global defaults in main() before the app renders. The example app uses custom dialog labels, custom buttons, rounded introduce styling, and disabled child animation:
voidmain() {
FeaturesTour.setGlobalConfig(
preDialogConfig: PreDialogConfig(
enabled: true,
title: 'Welcome to Features Tour',
content: 'This tour will guide you through the main features of the app.',
applyToAllCheckboxLabel: 'Apply to all pages',
acceptButtonLabel: 'Start Tour',
laterButtonLabel: 'Later',
dismissButtonLabel: 'Dismiss',
),
introduceConfig: RoundedRectIntroduceConfig(),
childConfig: ChildConfig(isAnimateChild: false),
skipConfig: SkipConfig(
builder: (context, onPressed) => ElevatedButton.icon(
onPressed: onPressed,
icon: constIcon(Icons.skip_next),
label: constText('SKIP'),
),
),
nextConfig: NextConfig(
builder: (context, onPressed) => FilledButton.icon(
onPressed: onPressed,
icon: constIcon(Icons.arrow_forward),
label: constText('NEXT'),
),
),
previousConfig: PreviousConfig(
builder: (context, onPressed) => FilledButton.icon(
onPressed: onPressed,
icon: constIcon(Icons.arrow_back),
label: constText('PREVIOUS'),
),
),
doneConfig: DoneConfig(
builder: (context, onPressed) => FilledButton.icon(
onPressed: onPressed,
icon: constIcon(Icons.done),
label: constText('DONE'),
),
),
debugLog: true,
);
runApp(constChangeableThemeMaterialApp());
}
Use ChildConfig for the highlighted area, IntroduceConfig for the callout, and the button configs for custom navigation affordances. PreDialogConfig controls the pre-tour confirmation dialog, including the optional apply-to-all-pages behavior.
Flow and Callbacks
TourAction describes the user action that reached or ended a step: introduce, next, previous, done, skip, disabled, and notMounted.
onBeforeAction runs before the step is introduced. The widget must already be mounted when this hook runs, so use it only for visible preparation like scrolling a list into view or reopening a surface that is already part of the widget tree. Do not use it to open a dialog for the current widget; trigger that from the previous step's onAfterAction instead. The first appearance of a step receives TourAction.introduce; returning to it from the next step receives TourAction.previous.
onAfterAction runs after the user chooses a navigation action from the current step. This is where the example app opens the drawer for the next surface, closes the drawer when going back, or opens a dialog after the last list item.
onStateChanged lets you observe the tour lifecycle. Common states include TourInProgress, TourIntroducing, TourPreDialogShownDefault, TourPreDialogShownCustom, TourCompleted, and TourEmpty.
Open the target surface from the previous step and let nextStep wait for the new widget to appear. This is the pattern used in the example app and in the drawer/dialog tests.
For dialogs, open the dialog from the prior step, then use a FeaturesTour inside the dialog content for the dialog-specific step.
Scroll-driven steps
Use onBeforeAction to scroll the current item into view before the introduction starts or when the user returns from the next step. The widget must already be mounted when this callback runs, so it is not a good place to open a dialog for the current step.
indexes is still supported for migration, but steps is the preferred API.
Customization Notes
IntroduceConfig can be customized with a builder, barrier color builder, padding, quadrant alignment, alignment, and root overlay support. RoundedRectIntroduceConfig() is the preset to use when you want a rounded callout with better contrast out of the box.
ChildConfig supports a custom wrapper builder, background color, shape border, animation settings, zoom scale, and border inflation around the highlighted child.
PreDialogConfig supports custom labels, button styles, callbacks, and a customDialogBuilder if you want to replace the default dialog entirely.
Migration Notes
0.6.0-0.7.0
Instantiate the new generic API as FeaturesTourController<YourStepEnum>('PageName') and FeaturesTour<YourStepEnum>(...).
Prefer step over index.
Prefer nextStep and nextStepTimeout over nextIndex and nextIndexTimeout.
Prefer FeaturesTourPadding.steps over FeaturesTourPadding.indexes.
Prefer onBeforeAction and onAfterAction over the deprecated onBeforeIntroduce and onAfterIntroduce callbacks.
Prefer onStateChanged over the deprecated onState callback. The older onState parameter is still supported for migration but will be removed in a future release.
If you don't want to use the previous action button, you can use this setting to keeps the old behavior: