How to get rid of load times for asset images in flutter - 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,
),

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 scroll underlying widget in Flutter?

I have a simple app with two screens. The first screen is a scrollable ListView and the second screen is basically empty and transparent. If I pushed the second screen with Navigator.push() on top of the first screen I'd like to be able to scroll the underlying first screen.
Here is my code:
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, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemBuilder: (context, index) {
return Text("$index");
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
PageRouteBuilder<void>(
opaque: false, // push route with transparency
pageBuilder: (context, animation, secondaryAnimation) => Foo(),
),
);
},
child: Icon(Icons.add),
),
);
}
}
class Foo extends StatelessWidget {
const Foo({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white.withOpacity(0.5),
appBar: AppBar(
title: Text("I'm on top"),
),
);
}
}
How can scroll the list in the backgound while the second screen is in the foreground?
Although this is not a solution with a second screen, it creates a similar effect using the Stack and IgnorePointer widgets:
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, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _applyOverlay = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: _applyOverlay
? IconButton(
icon: Icon(
Icons.arrow_back_ios_sharp,
),
onPressed: () => setState(
() => _applyOverlay = false,
),
)
: null,
title: Text(_applyOverlay ? 'Overlay active' : widget.title),
),
body: Stack(
children: [
ListView.builder(
itemBuilder: (context, index) {
return Text("$index");
},
),
if (_applyOverlay)
// Wrap container (or your custom widget) with IgnorePointer to ignore any user input
IgnorePointer(
child: Container(
height: double.infinity,
width: double.infinity,
color: Colors.white.withOpacity(0.5),
),
),
],
),
floatingActionButton: _applyOverlay
? null
: FloatingActionButton(
onPressed: () {
setState(() => _applyOverlay = true);
},
child: Icon(Icons.add),
),
);
}
}
I found a solution that works even with two screens. The idea is to have two ScrollControllers each in one screen and add a listener the ScrollController in the overlay that triggers the ScrollController of the underlying widget.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
const INITIAL_OFFSET = 5000.0;
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, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController controller = ScrollController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
controller: controller,
itemBuilder: (context, index) {
return Text("$index");
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
PageRouteBuilder<void>(
opaque: false, // push route with transparency
pageBuilder: (context, animation, secondaryAnimation) => Foo(
controller: controller,
),
),
);
},
child: Icon(Icons.add),
),
);
}
}
class Foo extends StatefulWidget {
final ScrollController controller;
const Foo({required this.controller, Key? key}) : super(key: key);
#override
State<Foo> createState() => _FooState();
}
class _FooState extends State<Foo> {
final ScrollController controller = ScrollController(
initialScrollOffset: INITIAL_OFFSET,
);
#override
void initState(){
super.initState();
controller.addListener(() {
widget.controller.animateTo(
controller.offset - INITIAL_OFFSET,
duration: const Duration(milliseconds: 1),
curve: Curves.linear,
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white.withOpacity(0.5),
appBar: AppBar(
title: Text("I'm on top"),
),
body: SingleChildScrollView(
controller: controller,
child: Container(
height: 2 * INITIAL_OFFSET,
color: Colors.white.withOpacity(0.5),
),
),
);
}
}
There are still a few problems with this workaround:
This does not work for infinite lists.
The scroll behavior is bad because the background is only scrolled when the scroller ends his gesture by put the finger up.
The sizes of the both screens doesn't match. That leads to bad effects like scrolling in areas that doesn't exists in the other screen.
I finally found a satisfying answer that does not contain any kind of dirty workarounds. I use a Listener in the second screen to detect OnPointerMoveEvents which are basically scroll events.
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, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController controller = ScrollController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
controller: controller,
itemBuilder: (context, index) {
return Text("$index");
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
PageRouteBuilder<void>(
opaque: false, // push route with transparency
pageBuilder: (context, animation, secondaryAnimation) => Foo(
controller: controller,
),
),
);
},
child: Icon(Icons.add),
),
);
}
}
class Foo extends StatefulWidget {
final ScrollController controller;
const Foo({required this.controller, Key? key}) : super(key: key);
#override
State<Foo> createState() => _FooState();
}
class _FooState extends State<Foo> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white.withOpacity(0.5),
appBar: AppBar(
title: Text("I'm on top"),
),
body: Listener(
onPointerMove: (event){
var newPosition = widget.controller.position.pixels - event.delta.dy;
widget.controller.jumpTo(newPosition);
},
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.red.withOpacity(0.5),
),
),
);
}
}

Error Missing concrete implementation of 'StatefulWidget.createState'. Try implementing the missing method, or make the class abstract

import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child:
Container(
height: 200,
width: 100,
color: Colors.yellow,
),
),
);
}
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("asset/image/Bestone.jpg")))));
}
}
No matter what I'm using, I have a problem when I'm trying to run or code. I get this error.
Missing concrete implementation of 'StatefulWidget.createState'. Try implementing the missing method, or make the class abstract for the MyApp ()
StatefulWidget requires override method createState So you must override that method. Remove the build method and specify the following line inside MyApp
#override
_MyHomePageState createState() => _MyHomePageState();
Full example with proper StateFulWidget
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: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
#override
_MyHomePageState 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: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
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),
),
);
}
}

Flutter: how to create moveable widget

I have tried to create a moveable text widget.
When I press on widget and start moving finger around screen (still pressing on widget), then position of widget should be also moved.
I have tried to do this with GestureDetector and Transform widgets.
Here is code:
import 'package:flutter/material.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> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MoveText(),
],
),
),
);
}
}
class MoveText extends StatefulWidget{
#override
_MoveTextState createState() => _MoveTextState();
}
class _MoveTextState extends State<MoveText> {
Offset offset = Offset(0.0, 0.0);
#override
Widget build(BuildContext context) {
return GestureDetector(
onLongPressMoveUpdate: (LongPressMoveUpdateDetails details) {
print('${details.localPosition}');
},
onPanStart: (details){
},
onPanUpdate: (details){
print('Pan update ${details.localPosition}');
setState((){
offset = details.localPosition;
});
},
onPanCancel: (){
print('Pan cancel');
},
child: Transform(
transform: Matrix4.translationValues(offset.dx, offset.dy, 0.0),
child: Container(
height: 50,
width: 200,
color: Colors.yellow,
child: Text('Some text for test'),
),
),
);
}
}
When I first tap on widget and start moving everything works great, but when I stop and want again to start moving, then onPanUpdate isn't called.
Does anyone have some solution for this problem?
What you need is a Draggable widget.
Visit for more info: https://api.flutter.dev/flutter/widgets/Draggable-class.html

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],
),
);
}
}