Show tooltip once page initialized - Flutter - flutter

I need to show a hint/tooltip for the userto indicate the user can get his current location by pressing the button. Have included the Tooltip in the code but only when the user does a long press of the button the tooltip is appearing, i want the tooltip to appear when the screen is initialized.
Code:
GlobalKey _toolTipKey = GlobalKey();
GestureDetector(
onTap: () {
final dynamic tooltip = _toolTipKey.currentState;
tooltip.ensureTooltipVisible();
},
child: Tooltip(
key: _toolTipKey,
message: 'Get current Location',
child: CircleAvatar(
radius: 30,
child: IconButton(
onPressed: getLocation,
icon: Icon(
Icons.my_location,
color: Colors.white,
),
),
),
),
)

I recently had to implement the same thing and I after lot of trying I managed to get it working.
You can use stateful widget and call the function to show tooltip in its initState. Now I got the same error as another person.
The method ensureTooltipVisible was called on null.
To solve this, I had to call
await Future.delayed(Duration(milliseconds: 10));
before ensureTooltipVisible() function.
#override
void initState() {
super.initState();
showTooltipIfOnboadingComplete();
}
and the function to show and close tooltip after certain amount of time,
Future showAndCloseTooltip() async {
await Future.delayed(Duration(milliseconds: 10));
tooltipkey.currentState.ensureTooltipVisible();
await Future.delayed(Duration(seconds: 4));
tooltipkey.currentState.deactivate();
}
you will also have to set you Tooltip widget trigger mode as TooltipTriggerMode.manual,
Here is complete code;
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const FloatingSupportButton()
);
}
}
class FloatingSupportButton extends StatefulWidget {
const FloatingSupportButton({Key? key}) : super(key: key);
#override
State<FloatingSupportButton> createState() => _FloatingSupportButtonState();
}
class _FloatingSupportButtonState extends State<FloatingSupportButton> {
// final GlobalKey<TooltipState> tooltipkey = GlobalKey<TooltipState>();
final tooltipkey = GlobalKey<State<Tooltip>>();
#override
void initState() {
super.initState();
showAndCloseTooltip();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Align(
alignment: Alignment.center,
child: Tooltip(
message: "Hello",
triggerMode: TooltipTriggerMode.manual,
key: tooltipkey,
preferBelow: false,
child: FloatingActionButton(
child: const Icon(Icons.add),
shape: const CircleBorder(
side: BorderSide(
color: Colors.white,
),
),
backgroundColor: const Color(0xFFc60c0c),
onPressed: () {
showAndCloseTooltip();
},
),
),
),
);
}
Future showAndCloseTooltip() async {
await Future.delayed(const Duration(milliseconds: 10));
// tooltipkey.currentState.ensureTooltipVisible();
final dynamic tooltip = tooltipkey.currentState;
tooltip?.ensureTooltipVisible();
await Future.delayed(const Duration(seconds: 4));
// tooltipkey.currentState.deactivate();
tooltip?.deactivate();
}
}
Have a great day everyone, hope this was helpful !!

You should use Statefulwidget and in initState write below code
import 'package:flutter/scheduler.dart';
#override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
// Flutter get callback here when screen initialized.
final dynamic tooltip = _toolTipKey.currentState;
tooltip.ensureTooltipVisible();
});
}
Here the Full Source code When you run the app it directly shows "Get current Location" tooltip
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({Key? key, required this.title}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
GlobalKey _toolTipKey = GlobalKey();
#override
void initState() {
super.initState();
SchedulerBinding.instance!.addPostFrameCallback((_) {
// Flutter get callback here when screen initialized.
final dynamic tooltip = _toolTipKey.currentState;
tooltip.ensureTooltipVisible();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Tooltip(
key: _toolTipKey,
message: 'Get current Location',
child: CircleAvatar(
radius: 30,
child: IconButton(
onPressed: () {},
icon: Icon(
Icons.my_location,
color: Colors.white,
),
),
),
),
],
),
),
);
}
}

Related

Setstate not working when adding a widget to the background? [SOLVED]

The widget I made for the background color is causing a problem.
There is a problem when a child widget is added to the Background Color widget I made. In this case setstate doesn't work.
Setstate not working when adding a widget to the background?
Why is the screen not updating?
Why do you think this is not happening? Where am I doing wrong?
//zemin_rengi.dart
import 'package:flutter/material.dart';
class ZeminRengi extends StatefulWidget {
final Widget childWidget;
const ZeminRengi({required this.childWidget});
#override
State<ZeminRengi> createState() => _ZeminRengiState();
}
class _ZeminRengiState extends State<ZeminRengi> {
Widget? _childWidget;
#override
void initState() {
// TODO: implement initState
super.initState();
_childWidget = widget.childWidget;
}
#override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.blue, Colors.red]),
),
child: _childWidget,
);
}
}
//main.dart
import 'package:builk/zemin_rengi.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: 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> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ZeminRengi(
childWidget: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
thanks for help.
enter image description here

How to get rid of load times for asset images in flutter

I am building an app that uses lots of images and I was wondering if there is a way to get rid of the time it takes for the image to load and show up on screen when the image is being called? Here is a simple example of an image that I want to be loaded that is contained inside of a visibility widget.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool isVis = false;
Widget _showAssetImage() {
return Visibility(
visible: isVis,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.amber,
image: DecorationImage(image: AssetImage('deer.jpg'))),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('test app'),
),
body: _showAssetImage(),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.image),
onPressed: () {
setState(() {
isVis = true;
});
},
),
);
}
}
you can try precacheImage():
final theImage = Image.asset("deer.jpg");
#override
void didChangeDependencies() {
precacheImage(theImage.image, context);
super.didChangeDependencies();
}
use it with:
Container(
width: 100,
height: 100,
child: theImage,
),

How to Change State of Material Button after a Delay?

I have a List of Emojis, [🤑, 👏, 👏🏻, 👏🏼, 👏🏽, 👏🏾, 👏🏿, 😍, 🥰, 😘, 😙, 😚, 🤗, 😻] with me, I also have a Button With me with no Icon Associated with it. See this Material Button.
MaterialButton(
onPressed: () {},
child: Text("",textScaleFactor: 2),
shape: CircleBorder(),
padding: EdgeInsets.all(16),
),
Now, I need to Show up the Above list, [🤑, 👏, 👏🏻, 👏🏼, 👏🏽, 👏🏾, 👏🏿, 😍, 🥰, 😘, 😙, 😚, 🤗, 😻] after a Delay of 1 sec, inside this Button.
You can also use Future.
MaterialButton(
onPressed: () async {
await Future<void>.delayed(Duration(seconds: 1));
// your function
},
child: Text('', textScaleFactor: 2),
shape: CircleBorder(),
padding: EdgeInsets.all(16),
),
You can use Timer.periodic to achieve this. See this sample code
Link to docs
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Timer emojiTimer;
#override
void initState() {
emojiTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
changeEmoji();
});
super.initState();
}
int randomInt = 0;
Future<void> changeEmoji() async {
setState(() {
var ran = Random();
randomInt = ran.nextInt(emojiList.length);
});
}
var emojiList = [
"🤑",
"👏",
" 👏🏻",
"👏🏼",
" 👏🏽",
" 👏🏾",
"👏🏿",
"😍",
"🥰",
"😘",
"😙",
"😚",
"🤗",
"😻"
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Text('hello there'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
emojiTimer.cancel();
},
child: Text(emojiList[randomInt]),
),
);
}
}

Flutter - Animate a widget to move from GridView to BottomBar upon tapping

I am looking to animate an image widget to move from a grid view to the bottom bar as shown below but much simpler. Could anyone provide me any guidance as to how to achieve this? I am leaning towards a transform animation, but I have hit a wall trying to calculate the source and destination screen points. Any help is highly appreciated.
Try this package, add_cart_parabola:
import 'dart:ui';
import 'package:add_cart_parabola/add_cart_parabola.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
GlobalKey floatKey = GlobalKey();
GlobalKey rootKey = GlobalKey();
Offset floatOffset ;
#override
void initState() {
// TODO: implement initState
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
RenderBox renderBox = floatKey.currentContext.findRenderObject();
floatOffset = renderBox.localToGlobal(Offset.zero);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
key: rootKey,
width: double.infinity,
height: double.infinity,
color: Colors.grey,
child: ListView(
children: List.generate(40, (index){
return generateItem(index);
}).toList(),
),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.yellow,
key: floatKey,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget generateItem(int index){
Text text = Text("item $index",style: TextStyle(fontSize:
25),);
Offset temp;
return GestureDetector(
onPanDown: (details){
temp = new Offset(details.globalPosition.dx, details.globalPosition
.dy);
},
onTap: (){
Function callback ;
setState(() {
OverlayEntry entry = OverlayEntry(
builder: (ctx){
return ParabolaAnimateWidget(rootKey,temp,floatOffset,
Icon(Icons.cancel,color: Colors.greenAccent,),callback,);
}
);
callback = (status){
if(status == AnimationStatus.completed){
entry?.remove();
}
};
Overlay.of(rootKey.currentContext).insert(entry);
});
},
child: Container(
color: Colors.orange,
child: text,
),
);
}
}

Conditional highlightColor on MaterialButton in flutter

I'm trying to build a quiz with multiple buttons. When the user presses the button for the right answer I want the button to have a highlightColor of green. If its the wrong button then the highlightColor is red. The issue I have is when I click a button the right highlightColor will show but you also get a glimpse of the wrong color. If I use the splashColor instead then you only see the right color which is good but the effect is not the same.
Here is a simplified version of the code with just one button but with the same issue.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
bool _winner = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Press the button:',
),
MaterialButton(
minWidth: MediaQuery.of(context).size.width * 0.90,
height: 60.0,
color: Colors.grey[800],
splashColor: Colors.transparent,
//splashColor: _winner ? Colors.green : Colors.red,
highlightColor: _winner ? Colors.green : Colors.red,
onPressed: () {
setState(() {
});
_winner ? _winner=false : _winner=true;
}
),
],
),
),
);
}
}
Thing here with the highlight fade animation that it last 200 milliseconds and the setState is called before the animation is over, thats why you get glimpse of the other color.
One solution is to setState after 200 milliseconds delay.
onPressed: () {
Future.delayed(Duration(milliseconds: 200), () {
setState(() {});
_winner ? _winner = false : _winner = true;
});
}),
another solution is to use GestureDetector with onTap event
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
bool _winner = true;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('widget.title'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Press the button:',
),
GestureDetector(
onTapDown: (_) {
setState(() {});
_winner ? _winner = false : _winner = true;
},
child: ColorButton(
isWinner: _winner,
),
),
],
),
),
);
}
}
class ColorButton extends StatefulWidget {
const ColorButton({
Key key,
#required this.isWinner,
}) : super(key: key);
final bool isWinner;
#override
_ColorButtonState createState() => _ColorButtonState();
}
class _ColorButtonState extends State<ColorButton> {
bool isPressed = false;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTapDown: (_) {
setState(() {
isPressed = true;
});
},
onTapUp: (_) {
setState(() {
isPressed = false;
});
},
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
height: 60.0,
width: MediaQuery.of(context).size.width * 0.9,
color: isPressed
? widget.isWinner ? Colors.green : Colors.red
: Colors.grey[800],
),
);
}
}