minaxorg / flutter_intro Goto Github PK
View Code? Open in Web Editor NEWThis project forked from tal-tech/flutter_intro
A better way for new feature introduction and step-by-step users guide for your Flutter project.
License: MIT License
This project forked from tal-tech/flutter_intro
A better way for new feature introduction and step-by-step users guide for your Flutter project.
License: MIT License
Hello,
Thank you for your awesome project. But I found a problem that if you use it in an ExpansionPanelRadioList, it will repeat some steps after one of the expansion panel expanded.
For example, you setup an intro step 100 for one of the expansion panel's headerBuilder, and intro step 101, 102 for other components in the page.
At step 101, I expanded the panel in the buttonTextBuilder, the step will be 100 again.
Normally, the order should be 100, 101, 102. But due to the problem, the order became 100, 101, 100, 102
I guess the problem is because of the rebuild of the panel. I decide whether to add an intro step temporarily to solve this problem by observing if the panel is expanded.
StepWidgetParams(
group: introStepBuilder.group,
order: introStepBuilder.order,
onNext: hasNextStep ? _render : null,
onPrev: hasPrevStep
? () {
_render(reverse: true);
}
: null,
onFinish: _onFinish,
screenSize: _screenSize,
size: _widgetSize,
offset: _widgetOffset,
),
在有下一步的情况下自定义OverlayBuilder使用不了onNext、onPrev方法,经测试hasNextStep、hasPrevStep判断有误
Hi, I'm trying to use this package as a desktop application, but I couldn't get it to work. However, I ran it in the mobile application. Then I saw that there is no web support in flutter 3, I wonder if it is not available for desktop applications at the moment?
第一次进去 App,需要使用框架介绍,后续就不用介绍,目前能实现这个功能吗?
Can this work in stateless widget ? Or only stateful?
I have this error :
E/flutter ( 7192): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: FlutterIntroException: The context does not contain an Intro widget.
E/flutter ( 7192): #0 Intro.of (package:flutter_intro/flutter_intro.dart:389:7)
E/flutter ( 7192): #1 _IntroStepBuilderState.initState. (package:flutter_intro/intro_step_builder.dart:60:34)
E/flutter ( 7192): #2 new Future.delayed. (dart:async/future.dart:427:39)
E/flutter ( 7192): #3 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15)
E/flutter ( 7192): #4 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
E/flutter ( 7192): #5 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
E/flutter ( 7192): #6 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:189:12)
E/flutter ( 7192):
单独跑 demo 没问题,但是按照 demo 加在页面里就出了这个错,百思不得其解
I'm using a bottom nav bar, specifically this https://pub.dev/packages/persistent_bottom_nav_bar_v2 and I'm wondering if it's possible to set this up so that on first load to highlight one of the bottom bar icons, then the user can click next which will navigate to a different page and highlight something else. like a completel tutorial or walk through of my app?
hi, when I start to run this page with 3 tabs and has it's floating action button(FAB), and I want to intro each FAB when tab was changed.
But I found when I press FAB to start intro, only tab 1 will show intro effect.
Then switch to tab 2 or tab 3, the FAB not display intro effect.
Below is my sample code, please help me.
Thank you very much.
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: Intro(
padding: EdgeInsets.zero,
borderRadius: const BorderRadius.all(Radius.circular(4)),
maskColor: const Color.fromRGBO(0, 0, 0, .6),
child: const MyHomePage(title: 'Flutter Demo Home Page'),
));
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
List tabs = ["Tab1", "Tab2", "Tab3"];
int _tabIndex = 0;
@override
void initState() {
super.initState();
_tabController = TabController(length: tabs.length, vsync: this);
_tabController.addListener(() {
var index = _tabController.index;
switch (index) {
case 0:
setState(() {
_tabIndex = 0;
});
break;
case 1:
setState(() {
_tabIndex = 1;
});
break;
case 2:
setState(() {
_tabIndex = 2;
});
break;
default:
break;
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("App Name"),
bottom: TabBar(
controller: _tabController,
tabs: tabs.map((e) => Tab(text: e)).toList(),
),
),
body: TabBarView(
controller: _tabController,
children: tabs.map((e) {
return KeepAliveWrapper(
child: Container(
alignment: Alignment.center,
child: Text(e, textScaleFactor: 5),
),
);
}).toList(),
),
floatingActionButton: _buildFab(),
);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
Widget _buildFab() {
return IntroStepBuilder(
order: 1,
group: _getGroupName(),
text: 'page: $_tabIndex',
builder: (context, key) => FloatingActionButton(
key: key,
backgroundColor: _getBgColor(),
onPressed: () {
Intro.of(context).start(group: _getGroupName());
},
child: Icon(_getIconData(), color: Colors.white, size: 25)),
);
}
String _getGroupName() {
String name = 'group$_tabIndex';
print('group name:$name');
return name;
}
Color _getBgColor() {
switch (_tabIndex) {
case 0:
return Colors.green;
case 1:
return Colors.red;
case 2:
return Colors.blue;
default:
return Colors.black;
}
}
IconData _getIconData() {
switch (_tabIndex) {
case 0:
return Icons.add;
case 1:
return Icons.access_time;
case 2:
return Icons.add_a_photo;
default:
return Icons.abc_sharp;
}
}
}
@hellohejinyu please create a migration document from v2 to 3, the example and readme are not very intuitive.
Great package!, but I have one issue, how to use this package to ListTile?, specifically I want to use the IntroStepBuilder in the index 0 of my ListTile, is it possible?
Hi,
I am encountering an issue when using the library on Android Web. When running the application on a web browser on an Android phone, the introstep feature does not work as expected. The element is not highlighted, and the background is not darkened, making the text unreadable. Interestingly, the issue seems to be specific to Android devices, as it works flawlessly on other platforms. Screenshots from an iPhone 12 Pro show the correct behavior, while those from a Pixel 6 do not.
hi,
I used IntroStepBuilder in different pages of my app. And in order to explain all my pages, I need to move through the pages with Get.to( ()=> NewPage()) like:
IntroStepBuilder(
order: 15,
overlayBuilder: (StepWidgetParams params) => IntroWidget( //my custom card intro widget
introText[14],
params,
previousCallBack: () async{ //when client click on previous button
Get.back();
await Future.delayed(Duration(seconds: 1));
params.onPrev!();
}
nextCallBack: () async { //when client click on next button
Get.to( ()=> NewPage());
await Future.delayed(Duration(milliseconds: 1000));
params.onNext!();
},
),
builder: (context, key) => Container(
key: key,
child: ....
)
)
Now I want to close the existing page and go back to the main page and enter another page from there.
The first problem is that you have to delay the code params.onNext!(); run Because the full page is not loaded. I think it should have a listener to load the next IntroStepBuilder whenever the full page is loaded. The next problem is that Get.back(); It causes the code params.onNext!(); have the following error
E/flutter ( 4333): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Null check operator used on a null value
E/flutter ( 4333): #0 Element.widget (package:flutter/src/widgets/framework.dart:3474:31)
E/flutter ( 4333): #1 debugCheckHasMediaQuery. (package:flutter/src/widgets/debug.dart:296:17)
E/flutter ( 4333): #2 debugCheckHasMediaQuery (package:flutter/src/widgets/debug.dart:311:4)
E/flutter ( 4333): #3 MediaQuery._of (package:flutter/src/widgets/media_query.dart:1169:12)
E/flutter ( 4333): #4 MediaQuery.of (package:flutter/src/widgets/media_query.dart:1165:12)
E/flutter ( 4333): #5 Intro._render (package:flutter_intro/flutter_intro.dart:199:30)
E/flutter ( 4333): #6 _TargetEditorPageState.build.. (package:habi/app/pages/basePages/targetEditorPage.dart:309:27)
E/flutter ( 4333):
hi,
Thank you for your previous reply, but I found another issue with switching tab by pressing tab or slide.
I want to start intro FAB automatically when tab was switched, so I call Intro.of(context).start() in onWidgetLoad() which in FAB.
Then switching tab by pressing tab or sliding with gesture, I will get some exception.
I am using version 3.2.1 of flutter_intro package.
The below is my sample code, please help me.
Thank you very much.
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: Intro(
padding: EdgeInsets.zero,
borderRadius: const BorderRadius.all(Radius.circular(4)),
maskColor: const Color.fromRGBO(0, 0, 0, .6),
child: const MyHomePage(title: 'Flutter Demo Home Page'),
));
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
List tabs = ["Tab1", "Tab2", "Tab3"];
int _tabIndex = 0;
@override
void initState() {
super.initState();
_tabController = TabController(length: tabs.length, vsync: this);
_tabController.addListener(() {
var index = _tabController.index;
switch (index) {
case 0:
setState(() {
_tabIndex = 0;
});
break;
case 1:
setState(() {
_tabIndex = 1;
});
break;
case 2:
setState(() {
_tabIndex = 2;
});
break;
default:
break;
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IntroStepBuilder(
group: 'group0',
order: 1,
text: 'Navigation Menu',
builder: (context, key) => IconButton(
key: key,
onPressed: () {
// Scaffold.of(context).openDrawer();
},
icon: const Icon(Icons.menu),
),
),
title: const Text("App Name"),
bottom: TabBar(
controller: _tabController,
tabs: tabs.map((e) => Tab(text: e)).toList(),
),
),
body: TabBarView(
controller: _tabController,
children: tabs.map((e) {
return KeepAliveWrapper(
child: Container(
alignment: Alignment.center,
child: Text(e, textScaleFactor: 5),
),
);
}).toList(),
),
floatingActionButton: _buildFab(),
);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
Widget _buildFab() {
return IntroStepBuilder(
order: 2,
group: _getGroupName(),
text: 'page: $_tabIndex',
onWidgetLoad: () {
Intro.of(context).start(group: _getGroupName());
},
builder: (context, key) => FloatingActionButton(
key: key,
backgroundColor: _getBgColor(),
onPressed: () {
},
child: Icon(_getIconData(), color: Colors.white, size: 25)),
);
}
String _getGroupName() {
String name = 'group$_tabIndex';
print('group name:$name');
return name;
}
Color _getBgColor() {
switch (_tabIndex) {
case 0:
return Colors.green;
case 1:
return Colors.red;
case 2:
return Colors.blue;
default:
return Colors.black;
}
}
IconData _getIconData() {
switch (_tabIndex) {
case 0:
return Icons.add;
case 1:
return Icons.access_time;
case 2:
return Icons.add_a_photo;
default:
return Icons.abc_sharp;
}
}
}
Here is two types exception I got
======== Exception caught by widgets library =======================================================
The following FlutterIntroException was thrown building RotationTransition(listenable: AnimationController#1859d(⏭ 1.000; paused)➩CurveTween(curve: Cubic(0.42, 0.00, 1.00, 1.00))➩Tween<double>(0.875 → 1.0)➩1.0➩TrainHoppingAnimation(next: _AnimationSwap<double>(AnimationController#0fe8e(⏭ 1.000; paused)➩Tween<double>(0.75 → 1.0)➩1.0, AnimationController#0fe8e(⏭ 1.000; paused)➩CurveTween(curve: Threshold)➩1.0➪ReverseAnimation)), state: _AnimatedState#8d1a2):
The current context is null, because there is no widget in the tree that matches this global key. Please check whether the key in IntroStepBuilder(group: group2, order: 2) has forgotten to bind. If you are already bound, it means you have encountered a bug, please let me know.
The relevant error-causing widget was:
Scaffold Scaffold:file:///C:/Users/EthanLee/AndroidProject/Sarun/flutter/QVPN/lib/main2.dart:86:12
When the exception was thrown, this was the stack:
#0 Intro._render (package:flutter_intro/flutter_intro.dart:217:7)
#1 Intro.start (package:flutter_intro/flutter_intro.dart:407:5)
#2 _MyHomePageState._buildFab.<anonymous closure> (package:qvpn/main2.dart:133:27)
#3 _IntroStepBuilderState.didUpdateWidget (package:flutter_intro/intro_step_builder.dart:83:28)
#4 StatefulElement.update (package:flutter/src/widgets/framework.dart:5652:55)
#5 Element.updateChild (package:flutter/src/widgets/framework.dart:3824:15)
#6 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6765:14)
#7 Element.updateChild (package:flutter/src/widgets/framework.dart:3824:15)
======== Exception caught by widgets library =======================================================
The following _TypeError was thrown building RotationTransition(listenable: AnimationController#0c617(⏭ 1.000; paused)➩CurveTween(curve: Cubic(0.42, 0.00, 1.00, 1.00))➩Tween<double>(0.875 → 1.0)➩1.0➩TrainHoppingAnimation(next: _AnimationSwap<double>(AnimationController#8b518(⏭ 1.000; paused)➩Tween<double>(0.75 → 1.0)➩1.0, AnimationController#8b518(⏭ 1.000; paused)➩CurveTween(curve: Threshold)➩1.0➪ReverseAnimation)), state: _AnimatedState#bba98):
Null check operator used on a null value
The relevant error-causing widget was:
Scaffold Scaffold:file:///C:/Users/EthanLee/AndroidProject/Sarun/flutter/QVPN/lib/main2.dart:86:12
When the exception was thrown, this was the stack:
#0 _IntroStepBuilderState.didUpdateWidget (package:flutter_intro/intro_step_builder.dart:80:61)
#1 StatefulElement.update (package:flutter/src/widgets/framework.dart:5652:55)
#2 Element.updateChild (package:flutter/src/widgets/framework.dart:3824:15)
#3 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6765:14)
#4 Element.updateChild (package:flutter/src/widgets/framework.dart:3824:15)
#5 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5505:16)
#6 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5643:11)
#7 Element.rebuild (package:flutter/src/widgets/framework.dart:5196:7)
There may be an obvious solution to this, but I'm trying to figure out how to use both flutter_intro and catcher, and they both wrap the root widget without returning a widget.
I can't provide Intro() as the rootWidget to Catcher(), and I can't provide Catcher() as the child to Intro(), since neither return a widget.
Does this make them incompatible, or are there any other options to implement Intro without having to remove catcher?
I added a delay of 1200 milliseconds and executed Intro. of (context). start();, Result IntroButton(
onPressed: params.onNext,
Text: 'Next step',
)This is not displayed
I am getting Multiple Global Key issues in my app when I try to show 2 or 3 IntroStepBuilder.
Hi,
Thanks for this nice package!
I just wanted to know how to initialize the Intro
if we plan to start a second intro sequence (the first being on app launch) on the same Page, only after the user performs an operation or presses a button.
How would both Intro
objects differentiate between each other's step order number 1?
Thanks!
it's possible to hide next button ?
i have a page in different dart file, i use intro in these file ,it can not work
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.