I had built an application and I'm trying to show feature discovery but, It is not showing discovery. Also not showing any error.
Question I Referred To Solve Issue
Main.dart
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) async {
runApp(
FeatureDiscovery(
child: MaterialApp(
home: SplashScreen(),
),
),
);
});
}
ServicesOffersReviewsPhotos.dart
class ServicesOffersReviewsPhotos extends StatefulWidget {
#override
_ServicesOffersReviewsPhotosState createState() =>
_ServicesOffersReviewsPhotosState();
}
class _ServicesOffersReviewsPhotosState
extends State<ServicesOffersReviewsPhotos>
with SingleTickerProviderStateMixin {
late TabController _controller;
#override
void initState() {
_controller = TabController(length: 4, vsync: this, initialIndex: 0);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: kOffWhiteBackGroundColor,
appBar: AppBar(
backgroundColor: kOffWhiteBackGroundColor,
elevation: 0,
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
color: kDarkGrey,
size: MediaQuery.of(context).size.width*0.05,
),
onPressed: () {
Navigator.pop(context);
},
),
actions: [
IconButton(
icon: Icon(
Icons.favorite_border,
color: kDarkGrey,
size: MediaQuery.of(context).size.width*0.05,
),
onPressed: () {},
),
IconButton(
icon: Icon(
Icons.share,
color: kDarkGrey,
size: MediaQuery.of(context).size.width*0.05,
),
onPressed: () {},
),
],
),
body: SafeArea(
child: DescribedFeatureOverlay(
featureId: 'add_item_feature_id', // Unique id that identifies this overlay.
tapTarget: const Icon(Icons.add), // The widget that will be displayed as the tap target.
title: Text('Add item'),
description: Text('Tap the plus icon to add an item to your list.'),
backgroundColor: Theme.of(context).primaryColor,
targetColor: Colors.black,
textColor: Colors.black,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
children's...
],
),
),
),
);
}
}
My Application Flow
SplashScreen (PushReplacement) -> onBoardingScreen(PushReplacement) -> LoginScreen(PushReplacement) -> Home(push) -> ServicesOffersReviewsPhotos
I have tried placing feature discovery on the top of servicesoffersReviewsPhotos Scaffold but didn't get any output.
I have referred every blog on medium, youtube videos. But didn't found any solution.
Question's probably old and abandoned but I think Feature Discovery is a great plugin with a lot of potential so, here goes...
I had cause to use the feature discovery plugin and ran into the same issue. After hours of reading their documentation, it turns out that the reason it seems like nothing is happening is because once the feature is show cased once or twice, Feature discovery automatically records that you have seen it in the shared preferences without telling you.
So, you'll notice that when you uninstall the app completely and clear all data, feature discovery seems to work again the first few times until it saves to shared preference again and doesn't seem to work again.
This is the expected behaviour in production environment as it saves you the hassle to writing an onComplete callback function that involves shared preferences.
For the sake of development, they provided this function
FeatureDiscovery.clearPreferences
It essentially deletes the shared preferences data. So you can see it as many times as you want.
But the neatest way to stop auto save to shared preferences is to set this
recordStepsInSharedPreferences: false,
or this
persistenceProvider: NoPersistenceProvider(),
as an argument to the FeatureDiscovery widget like this
home: FeatureDiscovery(
recordStepsInSharedPreferences: false,
child: DemoApp()
),
If none of these work, try using only the compulsory parameters of DescribedFeatureOverlay before adding optional parameters one by one and testing each to see the faulty code.
link to the pub
Cheers.
Related
I implemented an app that uses GNav from google_nav_bar.dart. Most things work fine and I really like it, i can manually switch pages by clicking on the tab icons of the navbar. But when I am trying to change the page in the code (e.g. Buttonpress or after the User did a certain action) with Navigator.pushNamed the navbar disappears. I know that this is normal bcs why should the navbar stay, but I have no idea how to manage this. There are not that many examples on the internet. Would be pretty nice if someone could help me!
Explanation of the app: the User scans a barcode of a book, and after the scan he gets redirected to the app page, where the user can find reviews to that book. And i want the navbar on that reviews page as well.
Here the simplified code where the navigation happens, the different screens just return a Scaffold, they are not implemented yet:
class MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
}
int _selectedIndex = 0;
static final List<Widget> _pages = <Widget>[
const ScannerScreen(),
const AllReviewsScreen(),
];
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('ReviewApp'),
),
body: _pages.elementAt(_selectedIndex),
bottomNavigationBar: Container(
color: Colors.black,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 0),
child: GNav(
gap: 8,
backgroundColor: Colors.black,
color: Colors.white,
activeColor: Colors.white,
tabBackgroundColor: Colors.grey.shade800,
padding: const EdgeInsets.all(12),
tabs: const [
GButton(
icon: Icons.qr_code_scanner,
text: 'Scanner',
),
GButton(
icon: Icons.reviews,
text: 'Alle Reviews',
),
],
selectedIndex: _selectedIndex,
onTabChange: (index) {
setState(() {
_selectedIndex = index;
});
},
),
),
),
),
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case '/scanner':
return FadeRoute(const ScannerScreen());
case '/all_reviews':
return FadeRoute(const AllReviewsScreen());
default:
return null;
}
});
}
}
I tried to use a tabController, but GoogleNavBar has no controller, so I think it handles this another way, but I hardly found stuff on the internet, in every example they only switch screen using the navbar. Of course i could just implement the navbar on every screen, but there must be an easier way
It is obvious behavior because when you call Navigator. push it immediately pushes the UI to a new screen where your bottomAppBar is not available.
Here is an article about what you want:
Multiple Navigators with BottomNavigationBar
Widget build(BuildContext context) {
print("homepage");
final navigation = Provider.of<NavigationProvider>(context, listen: false);
return Consumer<ThemeProvider>(builder: (context, themeData, _) {
return Scaffold(
backgroundColor: themeData.getTheme['mainBackground'],
appBar: AppBar(
backgroundColor: themeData.getTheme['appBar'],
elevation: 0.0,
title: Text(
"INTRADAE",
style: GoogleFonts.montserrat(
color: themeData.getTheme['textColor'],
),
),
actions: <Widget>[
Container(
margin: EdgeInsets.only(right: 5),
child: IconButton(
icon: Icon(
Icons.account_balance_wallet,
size: 30,
color: themeData.getTheme['textColor'],
),
onPressed: null,
),
)
],
),
body: Consumer<NavigationProvider>(
builder: (context, navigationProvider, _) =>
navigationProvider.getNavigation),
bottomNavigationBar: CurvedNavigationBar(
index: 0,
height: 50,
color: themeData.getTheme['secondaryBackground'],
backgroundColor: themeData.getTheme['mainBackground'],
buttonBackgroundColor: themeData.getTheme['mainBackground'],
items: <Widget>[
Icon(Icons.home, color: Colors.white),
Icon(Icons.shopping_cart, color: Colors.white),
Icon(Icons.person, color: Colors.white)
],
onTap: (index) {
navigation.updateNavigation(_pages[index]);
},
),
);
});
I am trying to update whatever is inside the body of the scaffold when updateNavigation takes place. Everything seemed fine, until I put a print inside the build method of the main widget and noticed that it was being called on every update the to NavigationProvider.
I am scratching my head since. I can't understand why this widget has to rebuild when only the Consumers should rebuild which in this case is inside the body of the Scaffold.
Coming from a React background this just seems weird to me.
Can anyone tell me why this is happening?
The problem was solved once I performed a hot restart. I then read about Hot Reload in Flutter the docs and realised that the changes I was making to the code weren't going to be seen unless I performed a hot restart.
Although the code posted here has
listen:false
in,
Provider.of<NavigationProvider>(context, listen: false)
But, I originally did not have that in my code. And when adding that argument too didn't seem to help, I decided to post a question here.
The problem was hot reload all along. Should've have made sure before posting.
I'm just starting to learn app development with Flutter.
I am trying to build an app for learning purposes that grabs an image from a website using their API to get a random image. The app displays the image, and has a button which is supposed to grab a new random image when pressed.
The problem is that the URL for the API doesn't change, so Flutter thinks the image is the same and doesn't download a new image. At least, that's what I think is going on.
The code is very basic. So far just showing an image and a button. I've tried various things, and was thinking imageCache.clear(); should do the job when the button is pushed, but nothing seems to work. I have also tried various tricks with resetting state and trying to navigate to the same page with named routes, but they all still show the same image (which is why I think it might be a caching issue). :shrug:
All of this is running from a single main.dart file.
import 'package:flutter/material.dart';
import 'package:transparent_image/transparent_image.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
backgroundColor: Colors.lightGreen[50],
appBar: AppBar(
title: Text("Show Me The Lettuce",
style: TextStyle(color: Colors.white70)),
backgroundColor: Colors.green[900],
),
body: ShowLettuce(),
),
),
);
}
class ShowLettuce extends StatefulWidget {
#override
_ShowLettuceState createState() => _ShowLettuceState();
}
class _ShowLettuceState extends State<ShowLettuce> {
String url = 'https://source.unsplash.com/900x900/?lettuce';
#override
Widget build(BuildContext context) {
return Center(
child: Column(
children: [
Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(80.0),
child: Center(child: CircularProgressIndicator()),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: FadeInImage.memoryNetwork(
placeholder: kTransparentImage, image: url),
),
],
),
SizedBox(
height: 20.0,
),
RaisedButton(
onPressed: () {
imageCache.clear();
print('button pressed.');
},
child: Text('Show Me A New Lettuce!'),
),
],
),
);
}
}
I've read through a lot of Flutter documentation, but I'm not yet at the point where I can interpret much of what they say into usable code (not sure where and how I'm supposed to plug it into my code, for example the imageCache documentation: https://api.flutter.dev/flutter/painting/ImageCache-class.html). It seems like this should be a really easy solution, but it is escaping me.
Any help is much appreciated.
I have solved you problem.
You must add for your code couple lines code:
as first - import:
import 'dart:math';
next - in class _ShowLettuceState after declared url variable:
var random = new Random();
and for finish - after click the button, namely in onPressed:
setState(() {
url = 'https://source.unsplash.com/900x900/?lettuce' + random.nextInt(100).toString();
});
I suggest you use this code :
String url = 'https://source.unsplash.com/900x900/?lettuce-${Random().nextInt(100)}';
This is inspired by #Captivity solution, but I add a - that makes it work.
To be able to use my icons, I upload them to fluttericon.com but it only accepts svg files. Since my icons are in .png format, I'm using a converter to convert them into svg. After the conversion, I upload them but it seems like they are not identified correctly by fluttericon.com, yet I'm unable to see icons on the app.
There is a custom bottom navigation bar in my app and it only accepts iconData as argument. So I have to use an actual icon. I tried using the custom icon on AppBar to be able know if it's bottom navigation bar causing the problem but it's same.
I read some comments saying the content of svg matters. Cause when I download a random icon in svg format directly and upload it, it's identified properly on fluttericon.com. What do I need to do?
Use icon: Image.asset("assets/home.png")
full code example:
class MyTabBar extends StatefulWidget {
#override
_MyTabBarState createState() => _MyTabBarState();
}
class _MyTabBarState extends State<MyTabBar> with TickerProviderStateMixin {
int tabIndex=0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.white,
child: tabIndex ==0 ?BottomTabBarHome()
:tabIndex == 1? BottomTabBarMail(): BottomTabBarProfile()
),
bottomNavigationBar: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Image.asset("assets/home.png", color: Colors.grey,),
activeIcon: Image.asset("assets/home.png", color: Colors.blue,),
title: Text('')
),
BottomNavigationBarItem(
icon: Image.asset("assets/mail.png", color: Colors.grey,),
activeIcon: Image.asset("assets/mail.png", color: Colors.blue,),
title: Text('')
),
BottomNavigationBarItem(
icon: Image.asset("assets/account.png", color: Colors.grey,),
activeIcon: Image.asset("assets/account.png", color: Colors.blue,),
title: Text('')
)
],
currentIndex: tabIndex,
selectedItemColor: Colors.blueAccent,
onTap: (int index){
setState(() {
tabIndex = index;
});
},
),
);
}
}
class BottomTabBarHome extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(" Home Screen"),
),
);
}
}
class BottomTabBarMail extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text("Mail Screen"),
),
);
}
}
class BottomTabBarProfile extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(" Profile Screen"),
),
);
}
}
pulled some code from my old project:
basic idea is that the icon or activeIcon named parameter asks for a Widget, includes but not limited to an Icon widget.
BottomNavigationBarItem(
title: Text('REALTIME SCHEDULE'),
activeIcon: TrackIcon(colorValue: Colors.white70),
icon: TrackIcon(colorValue: Color(0xff424150)),
),
class TrackIcon extends StatelessWidget {
final Color colorValue;
TrackIcon({#required this.colorValue});
#override
Widget build(BuildContext context) {
return SizedBox(
height: 33,
width: 99,
child: Image.asset(
'images/track_icon.png',
height: 25,
color: colorValue,
),
);
}
}
Here's how I used my png images as icons:
icon: const ImageIcon(
AssetImage('assets/image.png'),
),
It worked perfectly for me :).
As the above answers are useful (with just a few lines of edit), let me simplify
Use this line of code for using you PNG icons
icon: Image.asset("assets/home.png", color: Colors.grey,)
Now go to the folder containing the files of your flutter package for bottomNavigationBar and either edit the package itself OR copy the files into a folder flutterApp/packages/your_package/[those dart files] (second option is better to test with hot reload).
Note: flutterApp is the root folder of your flutter app.
Note: If you decided to edit the package itself in flutter/.pub-cache/hosted/... then you have to stop and re-run the debugging session after each edit for it to take effect.
Note: If you decided to copy the package files in your flutterApp then add them in your pubspecs.yaml as
dependencies:
your_package:
path: packages/your_package
Now, what to edit?
Find the constructor parameter icon or whatever it is. Now change its type from IconData (mostly) to Widget and now find the usage with simple searching/looking for the keyword and adjust/fit in the changed icon parameter as a Widget.
for example, if the usage looks something like this:
Icon(
widget.icon,
...
),
change it to:
widget.icon
because Icon() is also a widget which used the earlier IconData widget.icon and as we have converted that to Widget itself we can simply use widget.icon instead of Icon().
To add png to our code
add the below lines on pubspec.yaml
assets:
- lib/images/swap.png
in main.dart use the same directory
child: Image.asset('lib/images/swap.png')
HomeScreen() function call the Home screen of App.
How I Can route/move to "Team", "Add", etcetera page without BottomNavigationBar and AppBar.
I want show another page and back button, with new Bottom Navigation Bar.
I have this on my Flutter Project:
class APPMain extends StatefulWidget {
#override
_APPMainState createState() => _APPMainState();
}
class _APPMainState extends State<APPMain> {
int _currentIndex = 0;
_onTapped(int index) {
setState(() {
_currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
List<Widget> screens = [
HomeScreen(),
Center(child: Text("Team")),
Center(child: Text("Add")),
Center(child: Text("Search")),
Center(child: Text("Settings")),
];
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xffffffff),
iconTheme: IconThemeData(color: Colors.grey),
title: Text("Test App", style: TextStyle(color: Colors.grey),),
actions: <Widget>[
IconButton(
icon: Icon(Icons.account_circle),
onPressed: (){},
),
],
),
body: Container(
color: Color(0xfff4f4f4),
child: Center(
child: screens[_currentIndex],
),
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed,
fixedColor: Colors.red,
onTap: _onTapped,
items: [
BottomNavigationBarItem(
title: Text('Home'), icon: Icon(Icons.home)),
BottomNavigationBarItem(
title: Text('Team'), icon: Icon(Icons.group)),
BottomNavigationBarItem(
title: Text('Add'), icon: Icon(Icons.add)),
BottomNavigationBarItem(
title: Text('Search'), icon: Icon(Icons.search)),
BottomNavigationBarItem(
title: Text('Settings'), icon: Icon(Icons.settings)),
]),
);
}
}
Thank you so much for help.
This is almost certainly a duplicate but I wasn't able to find a question asking something similar with a quick search so I'll answer anyways.
The answer is actually quite simple, but requires understanding a bit more about how to write flutter applications - you should be using a Navigator or the navigator built right into MaterialApp or WidgetApp rather than making your own navigation. The simplest way is to use MaterialApp's routes property and pass in a map with each of your pages. Then when you want to switch pages, you simply use Navigator.pushNamed(context, <name>) from wherever you want to switch the page (i.e. a button).
The part that can be slightly confusing when you come from other frameworks is that rather than having one Scaffold and switching the body of it, the entire page should switch and each page should have a Scaffold.
Here's an example in the documentation showing how to navigate between pages.
For the record, although it's a bad idea you could make it work with your original code as well - all you'd have to do is build a different BottomNavigationBar with different options depending on what _currentIndex is set to. But I don't recommend that. With what I've suggested you also get animations between pages, back button functionality, you can hook up analytics to track page usage, and a bunch more things that flutter provides as part of navigation.