搜索插件、代码仓与 APP 分类

tutorial_coach_mark 封面
插件详情v1.3.4

tutorial_coach_mark

一个帮助您以美观、简洁且可自定义的方式展示您的应用及其功能的指南。教程 | 指南 | 教练。

AndroidiOSWebmacOSWindowsLinux
近 30 天下载
22.2万
喜欢数
1600
Pub 分数
150

安装插件

flutter pub add tutorial_coach_mark

插件介绍

基于插件公开信息、社区数据与项目使用情况整理的选型参考。

TutorialCoachMark 是一个专为 Flutter 设计的包,用于创建优雅且可自定义的应用程序引导教程和功能指南。它通过平滑的动画和提示气泡突出显示特定的用户界面元素,以引人入胜的方式帮助用户发现关键功能。非常适合介绍新功能或引导首次使用应用的用户完成应用工作流程。该包支持多种平台,包括 Android、iOS、Web、macOS、Windows 和 Linux,确保在各种设备上提供一致的用户体验。

适合场景

  • 引导新用户
  • 突出显示应用功能
  • 引导首次互动
  • 向用户教育关于新更新
  • 提高用户参与度

主要特点

  • 可自定义高亮形状
  • 流畅的动画过渡
  • 对多个平台的支持
  • 灵活的提示框定位
  • 可配置的叠加颜色
  • 与现有小部件的轻松集成

适合对象

  • 应用入门流程
  • 功能发现工具
  • 用户教育界面
  • 移动和网络应用
  • 寻求互动教程的设计师

使用建议

  • 可能需要仔细的布局规划
  • 使用大量标记时的性能影响
  • 有限的内置主题
  • 需要手动处理导航
  • 不适合复杂的多步骤工作流

原始 README

以下为关联源码仓库的 README 原文快照,最新内容请访问源码仓库。

pub package buymeacoffee

TutorialCoachMark

Create a beautiful and easy tutorial for your application.

Example 1 Example 2

Usage

To use this plugin, add tutorial_coach_mark as a dependency in your pubspec.yaml file.

Example
import 'package:flutter/material.dart';
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';

void showTutorial() {
    TutorialCoachMark tutorial = TutorialCoachMark(
      targets: targets, // List<TargetFocus>
      colorShadow: Colors.red, // DEFAULT Colors.black
       // opacityShadow = 0.8,
       // alignSkip: Alignment.bottomRight,
       // textSkip: "SKIP",
       // textStyleSkip: const TextStyle(color: Colors.white),
       // skipWidget: MyWidget(),
       // hideSkip: false
       // showSkipInLastTarget: true,
       // paddingFocus: 10,
       // focusAnimationDuration: Duration(milliseconds: 500),
       // unFocusAnimationDuration: Duration(milliseconds: 500),
       // pulseAnimationDuration: Duration(milliseconds: 500),
       // pulseVariation: Tween(begin: 1.0, end: 0.99),
       // pulseEnable: true,
       // imageFilter: ImageFilter.blur(sigmaX: 8, sigmaY: 8),
       // initialFocus: 0,
       // useSafeArea: true,
       // finish: (){},
       // clickTarget: (TargetFocus) {},
       // onClickTargetWithTapPosition: (TargetFocus, TapDownDetails) {},
       // clickOverlay: (TargetFocus) {},
       // disableBackButton: false // If true disable native back button. 
      onFinish: (){
        print("finish");
      },
      onClickTargetWithTapPosition: (target, tapDetails) {
        print("target: $target");
        print("clicked at position local: ${tapDetails.localPosition} - global: ${tapDetails.globalPosition}");
      },
      onClickTarget: (target){
        print(target);
      },
      onSkip: (){
        print("skip");
        return true;
      }
    )..show(context:context);

    // tutorial.skip();
    // tutorial.finish();
    // tutorial.next(); // call next target programmatically
    // tutorial.previous(); // call previous target programmatically
    // tutorial.goTo(3); // call target programmatically by index
  }
Creating targets (TargetFocus)

TargetFocus is the class that represents the widget that will be focused and configure what will be displayed after you focus it.

Attributes:

Attribute Type Description
identify dynamic free for identification use
keyTarget GlobalKey GlobalKey widget that wants to be focused
targetPosition TargetPosition If you do not want to use GlobalKey, you can create a TargetPosition to determine where to focus
contents ContentTarget[] Content list you want to display after focusing widget
shape ShapeLightFocus ShapeLightFocus.Circle or ShapeLightFocus.RRect
radius double Use when shape = ShapeLightFocus.RRect
borderSide BorderSide
color Color Custom color to target
enableOverlayTab bool enable click in all screen to call next step
enableTargetTab bool enable click in target to call next step
alignSkip Alignment use to align the skip in the target
paddingFocus Alignment settings padding of the focus in target
focusAnimationDuration Duration override the widget's global focus animation duration
unFocusAnimationDuration Duration override the widget's global unfocus animation duration
pulseVariation Tween override interval pulse animation
Creating contents (ContentTarget)

ContentTarget is the class responsible for determining what should be displayed and how it will appear after focusing on the widget.

Attributes:

Attribute Type Description
align AlignContent With this attribute you determine in which region to display the content in relation to the focused widget (top,bottom,left,right)
padding EdgeInsets Padding of the content
child Widget Content you want to be displayed
builder Widget Content you want to be displayed
customPosition CustomTargetContentPosition Add custom position when align is AlignContent.custom
Example Complete
import 'package:flutter/material.dart';
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';

List<TargetFocus> targets = List();

 @override
 void initState() {
    targets.add(
        TargetFocus(
            identify: "Target 1",
            keyTarget: keyButton,
            contents: [
              TargetContent(
                  align: ContentAlign.bottom,
                  child: Container(
                    child:Column(
                      mainAxisSize: MainAxisSize.min,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: <Widget>[
                        Text(
                          "Titulo lorem ipsum",
                          style: TextStyle(
                            fontWeight: FontWeight.bold,
                            color: Colors.white,
                            fontSize: 20.0
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.only(top: 10.0),
                          child: Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin pulvinar tortor eget maximus iaculis.",
                            style: TextStyle(
                                color: Colors.white
                            ),),
                        )
                      ],
                    ),
                  )
              )
            ]
        )
    );

    targets.add(
        TargetFocus(
            identify: "Target 2",
            keyTarget: keyButton4,
            contents: [
              TargetContent(
                  align: ContentAlign.left,
                  child: Container(
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: <Widget>[
                        Text(
                          "Multiples content",
                          style: TextStyle(
                              fontWeight: FontWeight.bold,
                              color: Colors.white,
                              fontSize: 20.0
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.only(top: 10.0),
                          child: Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin pulvinar tortor eget maximus iaculis.",
                            style: TextStyle(
                                color: Colors.white
                            ),),
                        )
                      ],
                    ),
                  )
              ),
              TargetContent(
                  align: ContentAlign.top,
                  child: Container(
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: <Widget>[
                        Text(
                          "Multiples content",
                          style: TextStyle(
                              fontWeight: FontWeight.bold,
                              color: Colors.white,
                              fontSize: 20.0
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.only(top: 10.0),
                          child: Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin pulvinar tortor eget maximus iaculis.",
                            style: TextStyle(
                                color: Colors.white
                            ),),
                        )
                      ],
                    ),
                  )
              )
            ]
        )
    );

    targets.add(
        TargetFocus(
            identify: "Target 3",
            keyTarget: keyButton5,
            contents: [
              TargetContent(
                  align: ContentAlign.right,
                  child: Container(
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: <Widget>[
                        Text(
                          "Title lorem ipsum",
                          style: TextStyle(
                              fontWeight: FontWeight.bold,
                              color: Colors.white,
                              fontSize: 20.0
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.only(top: 10.0),
                          child: Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin pulvinar tortor eget maximus iaculis.",
                            style: TextStyle(
                                color: Colors.white
                            ),),
                        )
                      ],
                    ),
                  )
              )
            ]
        )
    );
}

void showTutorial() {
    TutorialCoachMark(
      targets: targets, // List<TargetFocus>
      colorShadow: Colors.red, // DEFAULT Colors.black
       // alignSkip: Alignment.bottomRight,
       // textSkip: "SKIP",
       // paddingFocus: 10,
       // opacityShadow: 0.8,
      onClickTarget: (target){
        print(target);
      },
      onClickTargetWithTapPosition: (target, tapDetails) {
        print("target: $target");
        print("clicked at position local: ${tapDetails.localPosition} - global: ${tapDetails.globalPosition}");
      },
      onClickOverlay: (target){
        print(target);
      },
      onSkip: (){
        print("skip");
        return true;
      },
      onFinish: (){
        print("finish");
      },
    )..show(context:context);
  }

Contribution

If you find any errors or want to add improvements, you can open a issue or develop the fix and open a pull request. Thank you for your cooperation!

所属分类

源码仓库

使用此插件的项目