A better way for new feature introduction and step-by-step users guide for your Flutter project.

Related tags

UI flutter_intro
Overview

flutter_intro

pub package

A better way for new feature introduction and step-by-step users guide for your Flutter project.

Automatically adapt when the device screen orientation is switched.

Usage

To use this package, add flutter_intro as a dependency in your pubspec.yaml file.

Init

import 'package:flutter_intro/flutter_intro.dart';

Intro intro = Intro(
  /// You can set it true to disable animation
  noAnimation: false,

  /// The total number of guide pages, must be passed
  stepCount: 4,
  
  /// Click on whether the mask is allowed to be closed.
  maskClosable: true,
  
  /// When highlight widget is tapped.
  onHighlightWidgetTap: (introStatus) {
    print(introStatus);
  },

  /// The padding of the highlighted area and the widget
  padding: EdgeInsets.all(8),

  /// Border radius of the highlighted area
  borderRadius: BorderRadius.all(Radius.circular(4)),

  /// Use the default useDefaultTheme provided by the library to quickly build a guide page
  /// Need to customize the style and content of the guide page, implement the widgetBuilder method yourself
  /// * Above version 2.3.0, you can use useAdvancedTheme to have more control over the style of the widget
  /// * Please see https://github.com/tal-tech/flutter_intro/issues/26
  widgetBuilder: StepWidgetBuilder.useDefaultTheme(
    /// Guide page text
    texts: [
      'Hello, I\'m Flutter Intro.',
      'I can help you quickly implement the Step By Step guide in the Flutter project.',
      'My usage is also very simple, you can quickly learn and use it through example and api documentation.',
      'In order to quickly implement the guidance, I also provide a set of out-of-the-box themes, I wish you all a happy use, goodbye!',
    ],
    /// Button text
    buttonTextBuilder: (curr, total) {
      return curr < total - 1 ? 'Next' : 'Finish';
    },
  ),
);

Bind globalKey to widgets that need to be guided

The intro object in the first step contains the keys property, and keys is a globalKey array of length stepCount. Just bind the globalKey in the array to the corresponding component.

Placeholder(
  /// the first guide page is the first item in the binding keys
  key: intro.keys[0]
)

Run

That's it!

intro.start(context);

Custom widgetBuilder method

If you need to completely customize the style and content of the guide page, you need to implement the widgetBuilder method yourself.

final Widget Function(StepWidgetParams params) widgetBuilder;

This method will be called internally by flutter_intro when the intro page appears, and will pass some data on the current page in the form of parameters StepWidgetParams, and finally render the component returned by this method on the screen.

class StepWidgetParams {
  /// Return to the previous guide page method, or null if there is none
  final VoidCallback onPrev;

  /// Enter the next guide page method, or null if there is no
  final VoidCallback onNext;

  /// End all guide page methods
  final VoidCallback onFinish;

  /// Which guide page is currently displayed, starting from 0
  final int currentStepIndex;

  /// Total number of guide pages
  final int stepCount;

  /// The width and height of the screen
  final Size screenSize;

  /// The width and height of the highlighted component
  final Size size;

  /// The coordinates of the upper left corner of the highlighted component
  final Offset offset;
}

StepWidgetParams provides all the parameters needed to generate the guide page. The theme provided by default is also based on this parameter to generate the guide page.

Troubleshoot

Q1. What if the highlighted area is not displayed completely?

A1. That's because Intro provides 8px padding by default.

We can change it by setting the value of padding.

intro = Intro(
  ...,
  /// Set it to zero
  padding: EdgeInsets.zero,
);


Q2. Can I set different configurations for each step?

A2. Above version 0.4.x, you can set single or multiple step settings(padding & borderRadius) through setStepConfig and setStepsConfig.

intro.setStepConfig(
  1,
  padding: EdgeInsets.symmetric(
    vertical: -5,
    horizontal: -8,
  ),
);

intro.setStepsConfig(
  [0, 1],
  borderRadius: BorderRadius.all(
    Radius.circular(
      16,
    ),
  ),
);

Q3. Can I make the highlight area smaller?

A3. You can do it by setting padding to a negative number.

intro.setStepConfig(
  1,
  padding: EdgeInsets.symmetric(
    vertical: -10,
    horizontal: -8,
  ),
);


Q4. How can I manually destroy the guide page, such as the user pressing the back button?

A4. Above version 0.5.x, you can call the dispose method of the intro instance.

Notice: You can call the getStatus method only above version 2.1.0.

WillPopScope(
  child: Scaffold(...),
  onWillPop: () async {
    // sometimes you need get current status to make some judgements
    IntroStatus introStatus = intro.getStatus();
    if (introStatus.isOpen) {
      // destroy guide page when tap back key
      intro.dispose();
      return false;
    }
    return true;
  },
)

Q5: How to use in the web environment?

A5: Due to this bug in Flutter, it is temporarily not supported for use on the Web.(Update: It works in Flutter 2.0+)

Example

Please check the example in example/lib/main.dart.

Comments
  • 是否有更好的初始化intro的时机? Null check operator used on a null value

    是否有更好的初始化intro的时机? Null check operator used on a null value

    目前看example中是在state的构造函数中初始化的。

    intro肯定是要在build函数之前 , 因为build函数中会调用intro.keys[] 来设置key , 而因为intro中要设置UI,很有可能使用context,而过早初始化又获取不到context。

    还有一个问题是,我在调用intro.start(context)的时候 , 确认了context和intro都不为空, 但是报错:Null check operator used on a null value(通过catch intro.start(context) 获取到的信息)

    bug 
    opened by lizhuoyuan 7
  • Selected widget is darker than it should be

    Selected widget is darker than it should be

    Hi,

    Thanks for an amazing package! I think I did everything like in the example, but the widget that is supposed to be highlighted is darker than it should be for some reason. The colors that should be there are much lighter.

    image

    Maybe you can suggest what is causing this? I am not experienced with color blending at all.

    opened by boroma4 7
  • 能否添加intro显示队列

    能否添加intro显示队列

    你好, 这个插件真心不错,感谢!

    我使用的时候遇到了一些问题: 我引导的步骤是分多个Intro,当符合Intro触发条件后再显示该条件下的Intro。 所以就可能导致一个Intro还没引导完,另一个Intro就start了,这时就会覆盖到没完成的Intro上面,导致错乱

    现在的demo上,没找到结束监听,没办法知道上一个Intro是否处理完再处理下一个。能否添加一个队列或者一个结束的监听回调呢?

    谢谢

    enhancement 
    opened by zKidor 5
  • The message clips if intro is added to appbar leading or action buttons

    The message clips if intro is added to appbar leading or action buttons

    Hi, thank you for the great package. I was trying it out to review it on my Youtube channel, however, when I added the intro keys to Appbar buttons (leading and drawer) the messages and buttons were clipped. Here I have attached the screenshots.

    Screenshot_1601459623 Screenshot_1601460005

    good first issue 
    opened by lohanidamodar 5
  • 如何处理在不同界面比如tab加入引导,以及加入引导的时机

    如何处理在不同界面比如tab加入引导,以及加入引导的时机

    我这里需求是动态得 获取gloablkey,所以在网络请求之后获取到更新得位置,而且是加载tab上,导致传入全局得context,就是加载到区别的页面上,线上会报 Null check operator used on a null value 问题,还有个问题是出现了关闭不掉

     _lastScreenSize = MediaQuery.of(context).size;
    
    opened by a812358816 3
  • Failed to find render object

    Failed to find render object

    Hi, first of all I would like to thank for this super awesome package!

    Right now I'm stuck debugging this error _CastError (Null check operator used on a null value) to start the intro. After digging in, I found that it failed to get the currentContext from the global keys when trying to _getWidgetInfo. May I know what are the possibilities that might cause this issue?

    I'm having this problem when I want to auto start the intro. There's no problem if I manually start it.

    bug 
    opened by akifarhan 3
  • [Bug] No dark background in web

    [Bug] No dark background in web

    First I would like to thank you for this awesome package. It makes creating intros for an app very easy.

    I have tried to make an intro for a webapp too. It seems that there is no dark background, so the white text is impossible to read and the "continue" button is nearly impossible to tap.

    I'm using the version 0.5.1 of Flutter_intro and Flutter 1.23.0 in Beta channel.

    I have a workaround, by just wrapping the widgetbuilder into a container:

    final Intro roomsPageIntro = Intro(
        stepCount: 6,
        padding: EdgeInsets.all(8),
        borderRadius: BorderRadius.all(Radius.circular(4)),
        widgetBuilder: (step) => Container(
          color: kIsWeb ? Colors.black.withOpacity(0.5) : Colors.transparent,   // Workaround for web
          child: StepWidgetBuilder.useDefaultTheme(
            texts: [
              'Mit dieser Leiste bewegen Sie sich durch die Themen der App.',
              'Hier wählen Sie Unterkategorien zum Thema aus.',
              'Mit diesem Button fügen Sie neue Inhalte hinzu wie: Neue Chats mit Kollegen, neue Patienten, Anfragen, Todos, etc.',
              'Hier finden Sie alle Personen und Gruppen, mit denen Sie persönliche Chats haben.',
              'Hier finden Sie alle Patienten-zentrierten Chats.',
              'Hier finden Sie (bald) Zusatzangebote, wie Chat-Bots oder KI-Analysen.',
            ],
            btnLabel: 'Weiter',
            showStepLabel: true,
          )(step),
        ),
      );
    
    bug 
    opened by krillefear 3
  • First step message does not disappear

    First step message does not disappear

    Thank you for this awesome library.

    When I use combine this library with gen_l10n, a first step message does not disappear. There are any way to set messages from context?

    Code

      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        _startTutorial();
      }
    
      void _startTutorial() async {
        SharedPreferences pref = await SharedPreferences.getInstance();
        if (pref.getBool("showTutorial") ?? true == false) return;
    
        intro = Intro(
          stepCount: 6,
          maskClosable: true,
          widgetBuilder: StepWidgetBuilder.useDefaultTheme(
            texts: [
              AppLocalizations.of(context)!.tutorialSelectMusic,
              AppLocalizations.of(context)!.tutorialSetPointA,
              AppLocalizations.of(context)!.tutorialSetPointB,
              AppLocalizations.of(context)!.tutorialRepeatOn,
              AppLocalizations.of(context)!.tutorialSlide,
              AppLocalizations.of(context)!.tutorialAD,
            ],
            buttonTextBuilder: (currPage, totalPage) {
              return currPage < totalPage - 1
                  ? AppLocalizations.of(context)!.tutorialButtonNext
                  : AppLocalizations.of(context)!.tutorialButtonFinish;
            },
          ),
        );
    
        Timer(
          const Duration(
            milliseconds: 500,
          ),
          () {
            intro.start(context);
          },
        );
        pref.setBool("showTutorial", false);
      }
    

    pubspec.yaml

    dependencies:
      flutter_intro: ^2.3.1
    

    Screenshots

    1st step. 1st step

    2nd step. but 1st step message does not disappeared. 2nd step

    3rd step. 2nd step message disappeared, and 1st step message does not disappeared. 3rd step

    opened by OUDON 2
  • [Feature Request] Would be nice to have Skip/Close option in StepWidgetBuilder.useDefaultTheme

    [Feature Request] Would be nice to have Skip/Close option in StepWidgetBuilder.useDefaultTheme

    First of all thank you for the awesome package. I have a small default feature request, it would be nice to have Skip/Close button in StepWidgetBuilder.useDefaultTheme, as most of the use cases will need a Skip button, which is better than creating a custom widgetBuilder for most of the users. It should have these options:

    • StepWidgetBuilder.useDefaultTheme should have a parameter showSkip or showFinish
    • skipButtonTextBuilder to customize it's text
    • If it is the last index this should not be shown
    • Should have optional parameters to pass text style and button style e.g. skipButtonTextStyle, skipButtonStyle

    Same thing can be done for a Previous button, so that out-of-the-box the library provides easy customizations

    enhancement 
    opened by absar 2
  • support to style

    support to style

    it would be very interesting to be able to stylize the texts and buttons of the introduction to maintain the real identity of the application.

    Loving this package 😍

    opened by wesleytoshio 2
  • Allow tapping on the highlighted UI element

    Allow tapping on the highlighted UI element

    Hi,

    Great library. Could you add a VoidCallback for when a user taps on the highlighted UI element? Tapping to dismiss is OK but I want to let the user get through onboarding by actually tapping the buttons! Maybe another easier way would be to make the 'finish' callback available from the library.

    enhancement 
    opened by jagged91 2
  • Migration document from v2 to 3

    Migration document from v2 to 3

    @hellohejinyu please create a migration document from v2 to 3, the example and readme are not very intuitive. Secondly enable issue creation on the new repository, currently it is disabled: image

    opened by absar 0
  • 在 flutter_web 中使用 html 引擎渲染时无法显示灰色半透明遮罩

    在 flutter_web 中使用 html 引擎渲染时无法显示灰色半透明遮罩

    demo 链接位于 https://guest-card-testing.web.app/ 为了易于辨识,我将背景颜色改成了绿色。 这个问题会影响到在移动端 Safari 上运行时的显示效果。

    为了复现该问题,编译时采用 flutter build web --web-renderer html 命令,且在 web/index.html 的 head 中加入以下代码:

      <script type="text/javascript">
        // 强制使用 html 引擎渲染
        window.flutterWebRenderer = "html";
      </script>
    

    以下是示例代码:

    // main.dart
    import 'dart:async';
    
    import 'package:flutter/material.dart';
    import 'package:flutter_intro/flutter_intro.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: MyHomePage(
            title: 'Demo',
          ),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
    
      MyHomePage({
        Key? navKey,
        required this.title,
      }) : super(key: navKey);
    
      late final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      late Intro intro;
      late BuildContext globalContext;
    
      @override
      void initState() {
        super.initState();
        Future.delayed(Duration(seconds: 1), () {
          intro.start(globalContext);
        });
      }
    
      _MyHomePageState() {
        /// init Intro
        intro = Intro(
          stepCount: 4,
          maskClosable: true,
          onHighlightWidgetTap: (introStatus) {
            print(introStatus);
          },
    
          /// use defaultTheme
          widgetBuilder: StepWidgetBuilder.useDefaultTheme(
            texts: [
              'Hello, I\'m Flutter Intro.',
              'I can help you quickly implement the Step By Step guide in the Flutter project.',
              'My usage is also very simple, you can quickly learn and use it through example and api documentation.',
              'In order to quickly implement the guidance, I also provide a set of out-of-the-box themes, I wish you all a happy use, goodbye!',
            ],
            buttonTextBuilder: (currPage, totalPage) {
              return currPage < totalPage - 1 ? 'Next' : 'Finish';
            },
          ),
        );
      }
    
      Widget build(BuildContext context) {
        globalContext = context;
        return Scaffold(
          backgroundColor: Colors.green,
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: SingleChildScrollView(
            child: Container(
              padding: EdgeInsets.all(16),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  SizedBox(
                    width: 100,
                    child: Placeholder(
                      /// 2nd guide
                      key: intro.keys[1],
                      fallbackHeight: 100,
                    ),
                  ),
                  SizedBox(
                    height: 16,
                  ),
                  Placeholder(
                    /// 3rd guide
                    key: intro.keys[2],
                    fallbackHeight: 100,
                  ),
                  SizedBox(
                    height: 16,
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.end,
                    children: [
                      SizedBox(
                        width: 100,
                        child: Placeholder(
                          /// 4th guide
                          key: intro.keys[3],
                          fallbackHeight: 100,
                        ),
                      ),
                    ],
                  ),
                  ElevatedButton(
                      key: intro.keys[0],
                      onPressed: () {
                        intro.start(context);
                      },
                      child: Text("Press me"))
                ],
              ),
            ),
          ),
        );
      }
    }
    
    opened by the-eric-kwok 0
  • when the widget is scrollable, the highlight section goes off the screen

    when the widget is scrollable, the highlight section goes off the screen

    first of all, great plugin.

    just having an issue with a form which extents past the current view, the highlighted box is out of view with no option to scroll and just shows the back overlay.

    my current fix is having a custom call-back in useAdvancedTheme which will scroll to the key before running 'onNext' but could be a good feature.

    current solution

    inside Intro instance

    onTap: params.currentStepIndex == (params.stepCount - 1)
            ? () => {params.onFinish(), finishCallback()}
             : () async => {
                  await nextCallback(params.currentStepIndex + 1),
                  params.onNext(),
    },
    

    creating the intro instance with a function

    intro = createIntro(nextCallback: (index) async {
          print('next callback');
          await Scrollable.ensureVisible(intro.keys[index].currentContext,
              duration: Duration(seconds: 1));
        }, finishCallback: () {
          print('finish callback');
          Scrollable.ensureVisible(context);
    });
    
    enhancement 
    opened by andydean565 1
Owner
好未来技术
好未来开源
好未来技术
This Dart package offers developers a streamlined library of Flutter widgets, useful for expanding widgets and text views, when users interact with them.

This Dart package offers developers a streamlined library of Flutter widgets, useful for expanding widgets and text views, when users interact with them.

Jesús Rodríguez 44 Dec 6, 2022
A TypeAhead widget for Flutter, where you can show suggestions to users as they type

Flutter TypeAhead A TypeAhead (autocomplete) widget for Flutter, where you can show suggestions to users as they type Features Shows suggestions in an

null 661 Jan 5, 2023
A Flutter package that enables users to resize the internal widgets by dragging.

resizable_widget ResizableWidget enables users to resize the internal widgets by dragging. This package contains simple APIs, but if needed, you can c

null 35 Dec 2, 2022
Flutter Complete E-Commerce app (UI by - 'The Flutter Way')

NOT COMPLETED YET! e_commerce A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to ge

null 1 Mar 8, 2022
A simple way to bring drag’n’drop to flutter web

drop_zone is commonly used for file choosing by dragging and dropping a file(s) onto a designated widget. The user can then use the dropped html file(s).

Derrick Liu 32 Aug 2, 2022
A new Flutter package support scroll to index for Listview, Gridview and NestedScrollView

easy_scroll_to_index A new Flutter package support scroll to index for Listview, Gridview and NestedScrollView Author: DinhVanHung Demo Example: Displ

Dinh Hung 4 Nov 19, 2021
The Coolicons icon pack for Flutter with over 400 icons available for your flutter project.

coolicons This flutter package allows you to use the Coolicons icon pack. Made from Coolicons. ?? Installation In the dependencies: section of your pu

Stephen Joel 1 May 24, 2022
Foody - Flutter project to display foods to clients and display charts and has a lot of features , two flutter apps : Android and Web

Foody Flutter project to display foods to the clients and use charts and use a lot of features to complete the process (HUGE APP) There two apps: Andr

ABDULKARIMALBAIK 1 Feb 7, 2022
A nice clean onboarding screen for your e-commerce app that can run both Andriod and iOS devices because it builds with flutter

A nice clean onboarding screen for your e-commerce app that can run both Andriod and iOS devices because it builds with flutter

null 23 Dec 4, 2022
Keyviz is a free and open-source software to visualize your ⌨️ keystrokes in realtime

Keyviz is a free and open-source software to visualize your ⌨️ keystrokes in realtime! Let your audience know what handy shortcuts/keys you're pressing during screencasts, presentations, collaborations, or whenever you need it.

Derek Jones 8 Oct 31, 2022
A Flutter project that gives basic flutter design to implement a login UI

Login UI Design A Flutter project that gives basic flutter design to implement a

CABREX 9 Nov 8, 2022
Project Flutter which discusses how to create a movie dashboard UI

MOvApps (Flutter Project) Hi everybody. How are you guys? May you always be in good health and of course always be blessed by God! I want to showcase

Aqshal Rizqullah 1 Nov 30, 2021
Mi-card-app flutter project

my_card_app A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if t

null 1 Dec 2, 2021
ID-Card - A Simple ID Card Project Using Flutter

ID-CARD A new Flutter project.A simple demonstration of my time in the Dart lang

edwromero 0 Jan 26, 2022
This project contains various inspired UI kits purely coded in Flutter framework.

Flutter UI Kits This project contains various inspired UI kits purely coded in Flutter framework. Animated BottomBar (Fancy Bar v1.2.0) Available as a

Leo Elstin 1.2k Jan 8, 2023
An UI based flutter project.

Technoponics Table of Contents About The Project Built With Features Getting Started Roadmap Contact About The Project Technoponics is a app to know a

Yugal Panchal 1 Mar 15, 2022
An UI Design as an example to make a flutter project

Hello Guys! in this project i taked an UI Design as an example to make a flutter project. this project is the first part for figma to flutter...

Abdullah Kaşgar 10 Nov 22, 2022
A simple flutter UI project showing viewer a beautiful UI about coffee

coffee This is a simple flutter UI project where i am showing viewer a beautiful UI about coffee. And also i am using modular way to create this proje

Sarwar Murshed Shatil 5 Dec 13, 2022
Complete project of simple xylophone

xylophone A new Flutter application. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if

MD. ARIF ANZUM 0 Nov 26, 2021