animate show or hide widgets with flutter - flutter

i have something like this :
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _MyWidgetState();
}
}
class _MyWidgetState extends State<MyWidget> {
bool loading = true;
#override
Widget build(BuildContext context) {
if(loading) {
return Container(
color: Theme.of(context).scaffoldBackgroundColor,
child: Center(
child: SizedBox(
width: 24,
height: 24,
child: GestureDetector(
onTap: _toggle,
child: CircularProgressIndicator(),
),
),
),
);
} else {
return Container(
child: Center(
child: GestureDetector(
onTap: _toggle,
child: Text("WELCOME"),
),
),
);
}
}
_toggle() {
setState(() {
loading = !loading;
});
}
}
my big problem with flutter is animating between toggling widgets
i want when _toggle called, loading widget fadeOut and after animation completed remove from screen and then show normal widget with fadeIn effect
how can i achieved to this ?
thanks

Correct way is using AnimatedSwitcher widget:
class MyWidget extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _MyWidgetState();
}
}
class _MyWidgetState extends State<MyWidget> {
bool loading = true;
#override
Widget build(BuildContext context) {
return Scaffold(
body: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: loading ? Container(
key: Key("loading"),
color: Theme.of(context).scaffoldBackgroundColor,
child: Center(
child: SizedBox(
width: 24,
height: 24,
child: GestureDetector(
onTap: _toggle,
child: const CircularProgressIndicator(),
),
),
),
) : Container(
key: Key("normal"),
child: Center(
child: GestureDetector(
onTap: _toggle,
child: const Text("WELCOME"),
),
),
),
),
);
}
_toggle() {
setState(() {
loading = !loading;
});
}
}
note: you must give a key for children, in my example if you remove key animation not work

import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _MyWidgetState();
}
}
class _MyWidgetState extends State<MyWidget> {
bool loading = true;
#override
Widget build(BuildContext context) {
return Container(
child: Stack(
children: <Widget>[
Center(
child: GestureDetector(
onTap: _toggle,
child: Text("WELCOME"),
),
),
IgnorePointer(
ignoring: !loading,
child: AnimatedOpacity(
opacity: loading ? 1 : 0,
duration: Duration(milliseconds: 500),
child: Container(
color: Theme.of(context).scaffoldBackgroundColor,
child: Center(
child: SizedBox(
width: 24,
height: 24,
child: GestureDetector(
onTap: _toggle,
child: CircularProgressIndicator(),
),
),
),
),
),
)
],
),
);
}
_toggle() {
setState(() {
loading = !loading;
});
}
}

Related

Flutter VLC Player with options

import 'package:flutter/material.dart';
import 'package:flutter_vlc_player/flutter_vlc_player.dart';
class Home extends StatefulWidget {
#override
_ExampleVideoState createState() => _ExampleVideoState();
}
class _ExampleVideoState extends State<Home> {
final VlcPlayerController controller = new VlcPlayerController.network(url);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox(
height: 100,
width: 40,
child: new VlcPlayer(
aspectRatio: 16 / 9,
options : VlcPlayeroptions(),
controller: controller,
placeholder: Center(child: CircularProgressIndicator()),
)
)
);
}
}
this is my example where video is playing good, but i need to add options to it like play and pause, "options" is not working
i need to add play and pause button on vlc player in flutter app
Add a widget that sends play/pause through the controller class. Check out the other available methods too for the VlcPlayerController class.
ElevatedButton.icon(
onPressed: () => controller.pause(),
icon: const Icon(Icons.pause),
label: const Text('Pause'))
import 'package:flutter/material.dart';
import 'package:flutter_vlc_player/flutter_vlc_player.dart';
class Home extends StatefulWidget {
#override
_ExampleVideoState createState() => _ExampleVideoState();
}
class _ExampleVideoState extends State<Home> {
late bool _isplaying = true;
final VlcPlayerController controller = VlcPlayerController.network(
"url",
hwAcc: HwAcc.auto,
options: VlcPlayerOptions(),
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: <Widget>[
SizedBox(
width: MediaQuery.of(context).size.width,
height: 225,
child: VlcPlayer(
aspectRatio: 16 / 9,
controller: controller,
placeholder: const Center(child: CircularProgressIndicator()),
),
),
Container(
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
if (_isplaying)
TextButton(
onPressed: () {
controller.pause();
setState(() {
_isplaying = false;
});
},
child: const Icon(
Icons.play_arrow,
size: 50,
),
)
else
TextButton(
onPressed: () {
setState(() {
_isplaying = true;
controller.play();
});
},
child: Icon(
Icons.pause,
size: 50,
),
),
]),
),]
);
}
}
This is how i get it work done

AnimatedContainers with Row child not animating

I would like to use multiple animated containers, one for padding and another for height, but when I use a row, it stops animating. In my simplified code sample, you can see that the "Card View With Row..." card is not animating where the "Card View No Row..." is animating.
I imagine that it has something to do with the change in width and the row. Is there something I need to wrap my row in to make it compatible with the animated containers?
My desired outcome, I want
The padding around the column to animate
The height of the cards' headers to animate
The content to stay the same
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool cardView = true;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: AnimatedCardList(
isCardView: cardView,
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
cardView = !cardView;
});
},
backgroundColor: Colors.black,
child: Icon(
cardView ? Icons.check_rounded : Icons.edit,
size: 40,
color: Colors.white,
),
),
),
);
}
}
class AnimatedCardList extends StatelessWidget {
final bool isCardView;
const AnimatedCardList({
super.key,
required this.isCardView,
});
#override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(seconds: 2),
padding: isCardView ? EdgeInsets.zero : const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
BasicCard(
isCardView: isCardView,
header: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text("Card View With Row Not Animating"),
Text("Edit >"),
],
),
),
const SizedBox(height: 50),
BasicCard(
isCardView: isCardView,
header: const Text("Card View No Row IS Animating"),
),
],
),
);
}
}
class BasicCard extends StatelessWidget {
final Widget header;
const BasicCard({
Key? key,
required this.isCardView,
required this.header,
}) : super(key: key);
final bool isCardView;
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
child: Column(
children: [
AnimatedSize(
duration: const Duration(seconds: 2),
child: Container(
color: Colors.blue,
constraints: !isCardView
? const BoxConstraints(
maxHeight: double.infinity,
)
: const BoxConstraints(
maxHeight: 0.0,
),
child: header,
),
),
const Text("Card Content")
],
),
);
}
}
The problem:
Rows or Columns don't work well when their "cross axis" length is changed while wrapped in an animated widget. They already animate when their children are animating.
The solution:
Animate each of the children by wrapping them with the animation you want.
I created a AnimatedHeightCollapse widget that collapses based on a parameter. This should work for Column if you swich height with width respectively in the code.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool cardView = true;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: AnimatedCardList(
isCardView: cardView,
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
cardView = !cardView;
});
},
backgroundColor: Colors.black,
child: Icon(
cardView ? Icons.check_rounded : Icons.edit,
size: 40,
color: Colors.white,
),
),
),
);
}
}
class AnimatedCardList extends StatelessWidget {
final bool isCardView;
const AnimatedCardList({
super.key,
required this.isCardView,
});
#override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(seconds: 2),
padding: isCardView ? EdgeInsets.zero : const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
BasicCard(
header: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
AnimatedHeightCollapse(
visible: isCardView,
child: const Text("Card View With Row IS Animating"),
),
AnimatedHeightCollapse(
visible: isCardView,
child: const Text("Edit >"),
),
],
),
),
const SizedBox(height: 50),
BasicCard(
header: AnimatedHeightCollapse(
visible: isCardView,
child: const Text("Card View No Row IS Animating"),
),
),
],
),
);
}
}
class BasicCard extends StatelessWidget {
final Widget header;
const BasicCard({
Key? key,
required this.header,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
child: Column(
children: [header, const Text("Card Content")],
),
);
}
}
class AnimatedHeightCollapse extends StatelessWidget {
final bool visible;
final Widget child;
const AnimatedHeightCollapse({
super.key,
required this.visible,
required this.child,
});
#override
Widget build(BuildContext context) {
return AnimatedSize(
duration: const Duration(seconds: 2),
child: Container(
color: Colors.blue,
constraints: !visible
? const BoxConstraints(
maxHeight: double.infinity,
)
: const BoxConstraints(
maxHeight: 0.0,
),
child: child,
),
);
}
}

How can I properly remove an OverlayEntry in flutter?

In my main widget tree, I have a GestureDetector that when tapped, will launch an Overlay as follows:
OverlayState? _overlayState = Overlay.of(context);
_overlayState?.insert(
OverlayEntry(
builder: (BuildContext context) {
return ShowNotificationIcon();
},
)
);
SnowNotificationIcon is actually a StatefulWidget that houses the guts of the Overlay:
class ShowNotificationIcon extends ConsumerStatefulWidget {
const ShowNotificationIcon({Key? key}) : super(key: key);
#override
_ShowNotificationIconState createState() => _ShowNotificationIconState();
}
class _ShowNotificationIconState extends ConsumerState<ShowNotificationIcon> {
void initState(){
super.initState();
}
void dispose(){
super.dispose();
}
Positioned theDropDown(){
return
Positioned(
top: 50.0,
left: 50.0,
child: Material(
color: Colors.transparent,
child:
Column(children: [
Text('Test!'),
],)),
);
}
#override
Widget build(BuildContext context) {
return Stack(
children: [
Positioned.fill(
child: GestureDetector(
onTap: () {
/// I WANT TO REMOVE THE OVERLAY HERE
},
child: Container(
color: Colors.transparent,
),
)
),
theDropDown()
],
);
}
}
As I understand it, the overlay must be removed via a .remove() call, but since the overlay is all housed within a StatefulWidget, how can I make a .remove call on the overlay when it was opened outside of the StateWidget?
Am I missing something obvious here?
You can try this example I created for you
OverlayState? _overlayState = Overlay.of(context);
OverlayEntry? _overlayEntry;
_overlayEntry = OverlayEntry(
builder: (BuildContext context) {
return ShowNotificationIcon(entry: _overlayEntry);
},
);
_overlayState?.insert(_overlayEntry);
class ShowNotificationIcon extends ConsumerStatefulWidget {
final OverlayEntry? entry;
const ShowNotificationIcon({Key? key, this.entry}) : super(key: key);
#override
_ShowNotificationIconState createState() => _ShowNotificationIconState();
}
class _ShowNotificationIconState extends ConsumerState<ShowNotificationIcon> {
Positioned theDropDown(){
return
Positioned(
top: 50.0,
left: 50.0,
child: Material(
color: Colors.transparent,
child:
Column(children: [
Text('Test!'),
],)),
);
}
#override
Widget build(BuildContext context) {
return Stack(
children: [
Positioned.fill(
child: GestureDetector(
onTap: () {
if (widget.entry != null){
widget.entry.remove();
}
},
child: Container(
color: Colors.transparent,
),
)
),
theDropDown()
],
);
}
}
Here, A sample Toast class. I use close button in overlay. You can use similarly.
import 'package:flutter/material.dart';
class AppDialogs {
static final AppDialogs _instance = AppDialogs.internal();
AppDialogs.internal();
factory AppDialogs() => _instance;
static void appToast(
BuildContext context, {
required Widget title,
Widget? description,
Icon? toastIcon,
Color? toastColor,
double? height,
double? width,
bool dismissibleToast = true,
}) async {
final OverlayState? overlayState = Overlay.of(context);
late OverlayEntry overlayEntry;
overlayEntry = OverlayEntry(
builder: (content) => Positioned(
height: height ?? 80,
width: width ?? 200,
top: 0,
right: 0,
child: Card(
borderOnForeground: true,
elevation: 10,
child: Stack(
children: [
ListTile(
tileColor: toastColor,
title: title,
subtitle: description,
leading: toastIcon,
),
Positioned(
top: 0,
right: 0,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: InkWell(
onTap: () => closeOverlay(overlayEntry),
child: const Icon(
Icons.close,
size: 14,
),
),
),
),
],
))),
);
overlayState!.insert(overlayEntry);
}
static void closeOverlay(OverlayEntry overlayEntry) {
{
overlayEntry.remove();
}
}
}
class _LoginViewState extends State<LoginView> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
TextButton(
child: Text("Login"),
onPressed: (() {
AppDialogs.appToast(context, title: Text("Toast"));
}),
)
],
),
);
}

How to Navigate in Same the Page Master Detail page Flutter

I am building a master detail based app and I want to show in splitview. Trying to understand how to push data to another page in same view but couldn't. Want to cover details data in second page. How to push data?
It could be either responsive or not. But I don't want to resolve but only using set state and fill the blank in details 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> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.title,
style: TextStyle(color: Colors.black),
),
backgroundColor: Colors.transparent,
elevation: 0,
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: VerticalSplitView(
left: ListView.builder( itemCount: 12,
itemBuilder: (context, index) {
return Card(
child: InkWell(
splashColor: Colors.blue.withAlpha(30),
onTap: () {
//Navigator.push(context, MaterialPageRoute(builder: (context) => new yapiekle()) );
},
child: Container(
child: Padding(
padding: EdgeInsets.all(12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
//Center Column contents vertically,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: ListTile(
leading: Image.network("https://picsum.photos/200/300"),
title: Text("Title"),
subtitle: Text("Subtitle")),
),
//Spacer(),
],
),
),
),
),
);
}
),
right: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
),
child: Center(
child: FlutterLogo(
size: 256,
)),
),
),
),
);
}
}
class VerticalSplitView extends StatefulWidget {
final Widget left;
final Widget right;
final double ratio;
const VerticalSplitView(
{Key key, #required this.left, #required this.right, this.ratio = 0.5})
: assert(left != null),
assert(right != null),
assert(ratio >= 0),
assert(ratio <= 1),
super(key: key);
#override
_VerticalSplitViewState createState() => _VerticalSplitViewState();
}
class _VerticalSplitViewState extends State<VerticalSplitView> {
final _dividerWidth = 16.0;
//from 0-1
double _ratio;
double _maxWidth;
get _width1 => _ratio * _maxWidth;
get _width2 => (1 - _ratio) * _maxWidth;
#override
void initState() {
super.initState();
_ratio = widget.ratio;
}
#override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, BoxConstraints constraints) {
assert(_ratio <= 1);
assert(_ratio >= 0);
if (_maxWidth == null) _maxWidth = constraints.maxWidth - _dividerWidth;
if (_maxWidth != constraints.maxWidth) {
_maxWidth = constraints.maxWidth - _dividerWidth;
}
return SizedBox(
width: constraints.maxWidth,
child: Row(
children: <Widget>[
SizedBox(
width: _width1,
child: widget.left,
),
GestureDetector(
behavior: HitTestBehavior.translucent,
child: SizedBox(
width: _dividerWidth,
height: constraints.maxHeight,
child: RotationTransition(
child: Icon(Icons.drag_handle),
turns: AlwaysStoppedAnimation(0.25),
),
),
onPanUpdate: (DragUpdateDetails details) {
setState(() {
_ratio += details.delta.dx / _maxWidth;
if (_ratio > 1)
_ratio = 1;
else if (_ratio < 0.0) _ratio = 0.0;
});
},
),
SizedBox(
width: _width2,
child: widget.right,
),
],
),
);
});
}
}
I assumed that you want to change the the right page by clicking on the left card widgets. I have been developed something like this. I am using IndexedStack for render on the right side of VerticalSplitView then use provider and consumer for controlling the page to display.
First of all you need to import provider dependency in pubspec.ymal
You can replace this code below for entire of main.dart.
In main.dart you can try to replace this code. The idea is we are going to create IndexedStack that contain the Widget (Page as you prefer). Then we are going to change the index of IndexedStack by using Provider and Consumer.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_indexed_stack/page_data.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) {
var pageData = PageData();
return pageData;
}),
],
child: 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> {
// Set required page same as list length in left of VerticalSplitView
List<Widget> pages = [Text('Page1'), Text('Page2'), Text('Page3'),
Text('Page4'), Text('Page5'), Text('Page6'), Text('Page7'),
Text('Page8'), Text('Page9'), Text('Page10'), Text('Page11'),
Text('Page12'), ];
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.title,
style: TextStyle(color: Colors.black),
),
backgroundColor: Colors.transparent,
elevation: 0,
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: VerticalSplitView(
left: ListView.builder( itemCount: 12,
itemBuilder: (context, index) {
return Card(
child: InkWell(
splashColor: Colors.blue.withAlpha(30),
onTap: () {
// Set the current page for change page on the right side.
Provider.of<PageData>(context, listen: false).setCurrentTab(index);
},
child: Container(
child: Padding(
padding: EdgeInsets.all(12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
//Center Column contents vertically,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: ListTile(
leading: Image.network("https://picsum.photos/200/300"),
title: Text("Title"),
subtitle: Text("Subtitle")),
),
//Spacer(),
],
),
),
),
),
);
}
),
right: Consumer<PageData>(
builder: (context, pageData, child) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
),
child: IndexedStack(
children: pages,
index: pageData.currentPage,
)
);
},
),
),
),
);
}
}
class VerticalSplitView extends StatefulWidget {
final Widget left;
final Widget right;
final double ratio;
const VerticalSplitView(
{Key key, #required this.left, #required this.right, this.ratio = 0.5})
: assert(left != null),
assert(right != null),
assert(ratio >= 0),
assert(ratio <= 1),
super(key: key);
#override
_VerticalSplitViewState createState() => _VerticalSplitViewState();
}
class _VerticalSplitViewState extends State<VerticalSplitView> {
final _dividerWidth = 16.0;
//from 0-1
double _ratio;
double _maxWidth;
get _width1 => _ratio * _maxWidth;
get _width2 => (1 - _ratio) * _maxWidth;
#override
void initState() {
super.initState();
_ratio = widget.ratio;
}
#override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, BoxConstraints constraints) {
assert(_ratio <= 1);
assert(_ratio >= 0);
if (_maxWidth == null) _maxWidth = constraints.maxWidth - _dividerWidth;
if (_maxWidth != constraints.maxWidth) {
_maxWidth = constraints.maxWidth - _dividerWidth;
}
return SizedBox(
width: constraints.maxWidth,
child: Row(
children: <Widget>[
SizedBox(
width: _width1,
child: widget.left,
),
GestureDetector(
behavior: HitTestBehavior.translucent,
child: SizedBox(
width: _dividerWidth,
height: constraints.maxHeight,
child: RotationTransition(
child: Icon(Icons.drag_handle),
turns: AlwaysStoppedAnimation(0.25),
),
),
onPanUpdate: (DragUpdateDetails details) {
setState(() {
_ratio += details.delta.dx / _maxWidth;
if (_ratio > 1)
_ratio = 1;
else if (_ratio < 0.0) _ratio = 0.0;
});
},
),
SizedBox(
width: _width2,
child: widget.right,
),
],
),
);
});
}
}
You need to create file for Provider and replce the code below.
import 'package:flutter/cupertino.dart';
class PageData extends ChangeNotifier{
PageData();
int _currentPage = 0;
void setCurrentTab(int index){
this._currentPage = index;
notifyListeners();
}
int get currentPage {
return this._currentPage;
}
}
Happy coding :)
if I now want to place a button inside the right widget: "add new post". This new-post-function should create a new post by copying all data from current page to the new post with a new post-ID. In the same function it then should navigate into the new post to edit copy of comment in a copy of current post. Like:
ElevatedButton(
onPressed: () {
addPost();
}
)
addPost() {
String newId = uuid.v1();
var newPost = Entry(
id: newId,
entry: entryProvider.comment,
);
firestoreService.setEntry(newPost);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PostScreen(id: newId)));
}

Change image onTap

I was trying to change the image every time onTap.
But somehow the image is only getting changed only once.
Please review this piece of code and mention where am I going wrong
import 'package:flutter/material.dart';
class Demo extends StatefulWidget {
#override
_DemoState createState() => _DemoState();
}
String imagePath = "images/img4.jpg";
class _DemoState extends State<Demo> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: Container(
width: 100,
height: 100,
child: GestureDetector(
onTap: () {
setState(() {
imagePath = "images/tmhm.jpg";
});
},
child: CircleAvatar(
maxRadius: 20.0,
child: Image.asset(imagePath),
),
),
),
),
),
);
}
}
Place your imagePath in your State class(_DemoState)
import 'package:flutter/material.dart';
class Demo extends StatefulWidget {
#override
_DemoState createState() => _DemoState();
}
class _DemoState extends State<Demo> {
String imagePath = "images/img4.jpg";
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: Container(
width: 100,
height: 100,
child: GestureDetector(
onTap: () {
if(imagePath == "images/img4.jpg"){
imagePath = "images/tmhm.jpg";
}else{
imagePath = "images/img4.jpg";
}
setState(() {});
},
child: CircleAvatar(
maxRadius: 20.0,
child: Image.asset(imagePath),
),
),
),
),
),
);
}
}