Widget does not update properly after CircularProgressIndicator - flutter

I was trying to display a progress indicator on my app on flutter while it's loading. If I don't use it, the app works properly and the data load, but when I add the progress indicator, after it disappears, the app shows only the containers' borders or colors, without the data in them. How can I solve?
Here's the code of the main page:
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
bool isLoaded = false;
#override
void initState() {
super.initState();
DataSync data = DataSync();
data.getInitialData();
globals.isLoaded.addListener(() {
setState(() {
isLoaded = true;
});
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MainPage',
home: Scaffold(resizeToAvoidBottomInset: false, body: inizializeApp() ),
debugShowCheckedModeBanner: false,
);
}
Container inizializeApp() {
return Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomCenter,
colors: [
Color.fromARGB(255, 24, 26, 38),
Color.fromARGB(255, 1, 0, 5),
])),
//height: 500,
padding: const EdgeInsets.all(8),
child: Center(
child: isLoaded
? ListView(
physics: const NeverScrollableScrollPhysics(),
children: const [
SizedBox(height: 70, child: WeatherWidgets()),
SizedBox(height: 70, child: WeekDayWidget()),
SizedBox(height: 50, child: DateWidget()),
DataWidget(),
],
)
: const CircularProgressIndicator()),
);
}
}
and the class where I update the globals containing the data:
ValueNotifier<WeatherForecastResult> forecastResultNotifier =
ValueNotifier<WeatherForecastResult>(WeatherForecastResult.noParam());
ValueNotifier<int> selectedIndex = ValueNotifier<int>(0);
ValueNotifier<bool> isLoaded = ValueNotifier<bool>(false);
class DataSync {
Geolocation geolocation = Geolocation();
WeatherForecastResult forecastResult = WeatherForecastResult.noParam();
Weather weather = Weather();
getInitialData() async {
Position position = await geolocation.determinePosition();
forecastResult =
await weather.getForecast(position.latitude, position.longitude);
forecastResultNotifier.value = forecastResult;
isLoaded.value = true;
}
}
Tried various widget for the progress indicator, but the problem doesn't disappear

I tried to reproduce the problem - and failed! Could you check this simplified version (that should be complete in itself and run instantly) and try to reproduce the error? Or could you write a shortened version that is complete to run and reproduces the mistake? Then I would be happy to try to find out more!
import 'package:flutter/material.dart';
ValueNotifier<bool> globalIsLoaded = ValueNotifier<bool>(false);
class MyAppState extends State<MyApp> {
bool isLoaded = false;
Container initializeApp() {
return Container(
child: Center(
child: isLoaded
? const Text('is loaded')
: const CircularProgressIndicator(),
));
}
Container anotherInitializeApp() {
return Container(
child: Center(
child: ValueListenableBuilder(
builder: (BuildContext context, bool valueFromGlobalIsLoaded,
Widget? child) {
return valueFromGlobalIsLoaded
? const Text('is loaded')
: const CircularProgressIndicator();
},
valueListenable:
globalIsLoaded, // <-- ignores local isLoaded, so you would not need an addListener
),
));
}
#override
void initState() {
super.initState();
DataSync data = DataSync();
// data.getInitialData(); <-- moved it down after the addListener (but should not be decicive if this function is not super fast)
globalIsLoaded.addListener(() {
setState(() {
isLoaded = true;
});
});
data.getInitialData();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: initializeApp(), // try also: body: anotherInitializeApp(),
),
);
}
}
class DataSync {
getInitialData() async {
await Future.delayed(const Duration(seconds: 2));
globalIsLoaded.value = true;
}
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
MyAppState createState() => MyAppState();
}
void main() => runApp(MyApp());

Related

How can i update the UI on a ListView?

Every time i first run the code the list view don't show up, but if i do a hot reload the listView appear
List<JsonFetch> player = [];
String query = '';
Timer? debouncer;
class HomeScreen2 extends StatefulWidget {
const HomeScreen2({Key? key}) : super(key: key);
#override
State<HomeScreen2> createState() => _HomeScreen2State();
}
class _HomeScreen2State extends State<HomeScreen2> {
#override
void initState() {
super.initState();
init();
}
#override
void dispose() {
debouncer?.cancel();
super.dispose();
}
void debounce(
VoidCallback callback, {
Duration duration = const Duration(milliseconds: 1000),
}) {
if (debouncer != null) {
debouncer!.cancel();
}
debouncer = Timer(duration, callback);
}
Future init() async {
final players = await DataFromJson.getPlayer(query);
setState(() => player = players);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: const [
LeftSide(),
RightSide(),
],
),
);
}
}
I think the problem could be in the RightSide because is in a different class from HomeScreen2 and i don't pass some information correctly. I am a newbie on flutter and i can't reach the problem.
class RightSide extends StatefulWidget {
const RightSide({Key? key}) : super(key: key);
#override
State<RightSide> createState() => _RightSideState();
}
class _RightSideState extends State<RightSide> {
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
print(size);
return Expanded(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [AppColor.secondaryColor, AppColor.primaryColor],
stops: const [0.0, 1.0])),
child: Column(
children: [
WindowTitleBarBox(
child: Row(
children: [
Expanded(child: MoveWindow()),
const WindowButtons(),
],
),
),
Expanded(
child: ListView.builder(
itemCount: player.length,
itemBuilder: (context, index) {
final p = player[index];
return Shard(p);
},
))
],
),
),
);
}

how to change an image when I click a toggle button(flutter)

enter image description here
I cannot embed image because I don't have 10 reputation.
I want to load image when I click toggle buttons. it seems simple for you but it is hard for me to do it. I am a beginner .
I don't know how to write onPressed button. I already wrote onPressed buttons for toggle button. it seems like it is not possible to write one more oppressed code. I already used the onpressedbutton code to use ToggleButton, but I need one more function to load image but I don't know how to do it
enter code here
import 'package:flutter/material.dart';
import '123.dart';
import '456.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('imageToggle'),),
body: Column(
children: [
Expanded(child: Image.asset('images/meow.jpg')),
Button123(
),
Button456(),
],
),
),
);
}
}
class Button456 extends StatefulWidget {
#override
_Button456State createState() => _Button456State();
}
class _Button456State extends State<Button456> {
List<bool> isSelected = List.generate(3, (index) => false);
#override
Widget build(BuildContext context) {
return Container(
child: ToggleButtons(
isSelected: isSelected,
color: Colors.black,
fillColor: Colors.grey,
children: [
Padding(padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text('cat1'),),
Padding(padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text('cat2'),),
Padding(padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text('cat3'),),
],
onPressed: (int newIndexx) {
setState(() {
for (int index = 0; index < isSelected.length; index++) {
if (index == newIndexx) {
isSelected[index] = true;
} else {
isSelected[index] = false;
}
}
});
},
)
);
}
}
You can make the image url a variable.
String imageLink = 'myImage.png';
class _MyAppState extends State<MyApp> {
onButtonPressed(String value) {
setState(() {imageLink = value});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('imageToggle'),),
body: Column(
children: [
Expanded(child: Image.asset(imageLink)),
TextButton(child: Text('Click Me!'), onPressed: onButtonPressed('newImageLink')),
],
),
),
);
}
}

Pass the context to the showdialog so that it is not lost when the start page loads

I am trying to display an information dialog when starting an application.
After closing, another window appears asking for permission. I call it all in the initState function. It works, but I noticed that this first info dialog also closes on its own when 15 seconds have elapsed. As I understand, this is because the application has loaded and the context is lost.
And when I change runApp(MyApp()) to runApp(MaterialApp(home: MyApp())). It works, the popup doesn't dissapear. But the other showdialogs on other pages didn't close automatically (Navigator.of(context).pop() and Navigator.pop(context) doesnt work.
How do I properly pass context to my initial showdialog so that it doesn't disappear when the start page loads?
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
static final navKey = new GlobalKey<NavigatorState>();
const MyApp({Key navKey}) : super(key: navKey);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
final context = MyApp.navKey.currentState.overlay.context;
await showDialogIfFirstLoaded(context);
await initPlatformState();
});
}
showDialogIfFirstLoaded(BuildContext context, prefs) async {
bool isFirstLoaded = prefs.getBool(keyIsFirstLoaded);
if (isFirstLoaded == null) {
return showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return new AlertDialog(
// title: new Text("title"),
content: new Text("//"),
actions: <Widget>[
new FlatButton(
child: new Text(".."),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey:MyApp.navKey,
home: new SplashScreen(),}
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => new _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderStateMixin {
Timer _timer;
bool _visible = true;
startTime() async {
_timer = Timer(new Duration(seconds: 5), navigationPage);
}
void navigationPage() {
Navigator.of(context).pushReplacementNamed('/home');
}
#override
void initState() {
_timer = Timer(Duration(seconds: 4),
() => setState(
() {
_visible = !_visible;
},
),
);
startTime();
super.initState();
}
#override
void dispose() {
_timer.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Stack(
children: <Widget>[
Container(
width: double.infinity,
child: Image.asset('images/bg.jpg',
fit: BoxFit.cover,
height: 1200,
),
),
Container(
width: double.infinity,
height: 1200,
color: Color.fromRGBO(0, 0, 0, 0.8),
),
Container(
alignment: Alignment.center,
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
child: Text(''),
),
),
],
),
),
],
);
}
}

show button condition flutter

I would like my button to show only if my _isloading condition is false.
With my code the button appears but too early.
my widget:
i want my button after my timer set _isLoading = false.
Actually, my button show directly to start timer.
How do I get my button to only display when my timer set my _isLoading = false ?
First, you need to keep in mind the Flutter's tree widget structure. The tree hierachy should consists of only Widgets.
In your _validateUser(), since this method doesn't return a Widget, it cannot be put as a child of the Column widget. This method should be trigger by a button (after the user finish the form for example).
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
void main() {
runApp(MaterialApp(home: Home()));
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: TestPage(),
);
}
}
class TestPage extends StatefulWidget {
#override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
final _scaffoldKey = GlobalKey<ScaffoldState>();
bool _isLoading = false;
bool _isValidated = false;
_validateUser() async {
setState(() {
_isLoading = true;
});
await Future.delayed(Duration(seconds: 3), () {
setState(() {
_isLoading = false;
_isValidated = true;
});
});
}
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_validateUser();
});
super.initState();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
key: _scaffoldKey,
body: Center(
child: ModalProgressHUD(
inAsyncCall: _isLoading,
child: Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// FlatButton(
// color: Colors.red,
// child: Text("Validate User"),
// onPressed: _validateUser,
// ),
// SizedBox(height: 10),
if (_isValidated)
FlatButton(
color: Colors.green,
child: Text("Validate User"),
onPressed: _validateUser,
),
],
),
),
),
),
));
}
}

Flutter Web Mouse Region Widget Triggering

I am trying to get this result with Flutter;
I am having this behaviour;
Code;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:html' as html;
class OverlayAnimatedGridElement extends StatefulWidget {
OverlayAnimatedGridElement(this.imagepath, this.postDetail, this.postTitle);
final String imagepath;
final String postTitle;
final String postDetail;
#override
_OverlayAnimatedGridElementState createState() =>
_OverlayAnimatedGridElementState();
}
class _OverlayAnimatedGridElementState extends State<OverlayAnimatedGridElement>
with TickerProviderStateMixin {
AnimationController _controller;
Animation<double> _opacityTween;
bool isHovered = false;
#override
void initState() {
_controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 500));
_opacityTween = Tween<double>(begin: 0, end: 1).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeInOutCirc));
super.initState();
}
hoverActivation(hoverState) {
bool hoverState;
isHovered = hoverState;
if (isHovered = true) {
_controller.forward();
} else if (isHovered = false) {
_controller.reset();
}
print("activated");
}
#override
Widget build(BuildContext context) {
_opacityTween.addListener(() {
setState(() {
print(_opacityTween.value);
});
});
return MouseRegion(
onHover: hoverActivation(true),
child: Container(
constraints: BoxConstraints(maxHeight: 360, maxWidth: 640),
child: Stack(
alignment: Alignment.bottomCenter,
children: [
Image(image: AssetImage("${widget.imagepath}")),
Opacity(
opacity: _opacityTween.value,
child: Container(
color: Color.fromRGBO(128, 128, 128, 0.5),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("${widget.postDetail}"),
Text("${widget.postTitle}")
],
),
],
),
),
),
],
),
),
);
}
}
A standalone widget works okay but when I put it into gridview or pageview it automatically reads it mouse entered when I scroll into it.
I tried to use other widgets like Inkwell, Listener and others. No solution. Can someone guide me if there is better solution?
How Can I solve this?
edit:
Now having this problem. MouseRegion causes multiple controller.forwards
I am Created an Example ... please Try this,
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Todos',
theme: new ThemeData(primarySwatch: Colors.deepOrange),
home: MyHome(),
);
}
}
class MyHome extends StatelessWidget{
#override
Widget build(BuildContext context) {
return GridView.count(crossAxisCount: 3,
children: List.generate(10, (index) {
return OverlayAnimatedGridElement("https://picsum.photos/300/200");
}
));
}
}
class OverlayAnimatedGridElement extends StatefulWidget {
OverlayAnimatedGridElement(this.imagepath);
final String imagepath;
// final String postTitle;
// final String postDetail;
#override
_OverlayAnimatedGridElementState createState() =>
_OverlayAnimatedGridElementState();
}
class _OverlayAnimatedGridElementState extends State<OverlayAnimatedGridElement>
with TickerProviderStateMixin {
bool isHovered = false;
#override
void initState() {
super.initState();
}
hoverActivation(hoverState) {
setState(() {
isHovered = hoverState;
});
print("activated" + hoverState.toString());
}
#override
Widget build(BuildContext context) {
return Center(
child: Container(
color: Colors.red,
height: 200,
width: 300,
child: Stack(
children: [
Image.network(widget.imagepath),
MouseRegion(
onEnter: (event){
hoverActivation(true);
},
onExit: (event){
hoverActivation(false);
},
child: AnimatedContainer(
duration: Duration(milliseconds: 200),
color: Colors.black.withOpacity(isHovered ? 0.5 : 0),
),
)
],
),
),
);
}
}
I solved my second problem by just moving addListener method to initState. Previously it was inside widget itself which was causing adding listeners in every rebuild and causing multiple rebuilds for each listener, I guess.