Change image onTap - flutter

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

Related

how to perform drag operation on widget with Gesturedetector flutter

I want to drag and drop my custom widget with gesture detector. It is showing x- direction and y- direction values but not dragging to anywhere on screen.
Here is my code:
layoutpage:
SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Stack(
children: _layoutProvider.tables
.map(
(SectionTable sTable) => Positioned(
top: sTable.top,
left: sTable.left,
child: LayoutWidget(
width: sTable.width,
height: sTable.height,
type: sTable.type.index,
name: sTable.name,
left: sTable.left,
top: sTable.top,
rotate: sTable.rotate,
color: sTable.order != null
? Colors.green
: Colors.grey,
seats: sTable.seats,
),
),
)
.toList()),
),
LayoutWidget:
class LayoutWidget extends StatefulWidget {
late double width;
late double height;
late double left;
late double top;
LayoutWidget({
Key? key,
required this.width,
required this.height,
required this.left,
required this.top,
}) : super(key: key);
#override
State<StatefulWidget> createState() => _LayoutWidgetState();
}
class _LayoutWidgetState extends State<LayoutWidget> {
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
RotationTransition(
turns: widget.type == 0
? const AlwaysStoppedAnimation(0)
: AlwaysStoppedAnimation(rotationValue / 360),
child: GestureDetector(
onPanUpdate: (details) {
widget.top = widget.top+ details.delta.dy;
widget.left = widget.left+ details.delta.dx;
setState(() {
});
},
onTap: () {
setState(() {
showMenu = !showMenu;
});
},
child: myWidget()
}
Can anyone help why i am unable to drag on screen. Thanks.
I hope you you can get Idea from this code. In this code you can drag Container anywhere in the Screen and set it. And also check this Gesture Detector Overview for Gesture Detector detail.
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class GestureDetectorPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.grey[100],
width: double.infinity,
height: double.infinity,
child: MainContent(),
),
);
}
}
class MainContent extends StatefulWidget {
#override
_MainContentState createState() => _MainContentState();
}
class _MainContentState extends State<MainContent> {
GlobalKey key = GlobalKey();
String dragDirection = '';
String startDXPoint = '50';
String startDYPoint = '50';
String dXPoint;
String dYPoint;
String velocity;
#override
Widget build(BuildContext context) {
return GestureDetector(
onHorizontalDragStart: _onHorizontalDragStartHandler,
onVerticalDragStart: _onVerticalDragStartHandler,
onHorizontalDragUpdate: _onDragUpdateHandler,
onVerticalDragUpdate: _onDragUpdateHandler,
onHorizontalDragEnd: _onDragEnd,
onVerticalDragEnd: _onDragEnd,
dragStartBehavior: DragStartBehavior.start, // default
behavior: HitTestBehavior.translucent,
child: Stack(
children: [
Positioned(
left: double.parse(this.startDXPoint),
top: double.parse(this.startDYPoint),
child: Container(
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(100)
),
child: Center(
child: Padding(
padding: const EdgeInsets.all(20),
child: Text('Draggable', style: TextStyle(fontSize: 14, color: Colors.white),),
),
),
)
),
],
),
);
}
void _onHorizontalDragStartHandler(DragStartDetails details) {
setState(() {
this.dragDirection = "HORIZONTAL";
this.startDXPoint = '${details.globalPosition.dx.floorToDouble()}';
this.startDYPoint = '${details.globalPosition.dy.floorToDouble()}';
});
}
/// Track starting point of a vertical gesture
void _onVerticalDragStartHandler(DragStartDetails details) {
setState(() {
this.dragDirection = "VERTICAL";
this.startDXPoint = '${details.globalPosition.dx.floorToDouble()}';
this.startDYPoint = '${details.globalPosition.dy.floorToDouble()}';
});
}
void _onDragUpdateHandler(DragUpdateDetails details) {
setState(() {
this.dragDirection = "UPDATING";
this.startDXPoint = '${details.globalPosition.dx.floorToDouble()}';
this.startDYPoint = '${details.globalPosition.dy.floorToDouble()}';
});
}
/// Track current point of a gesture
void _onHorizontalDragUpdateHandler(DragUpdateDetails details) {
setState(() {
this.dragDirection = "HORIZONTAL UPDATING";
this.dXPoint = '${details.globalPosition.dx.floorToDouble()}';
this.dYPoint = '${details.globalPosition.dy.floorToDouble()}';
this.velocity = '';
});
}
/// Track current point of a gesture
void _onVerticalDragUpdateHandler(DragUpdateDetails details) {
setState(() {
this.dragDirection = "VERTICAL UPDATING";
this.dXPoint = '${details.globalPosition.dx.floorToDouble()}';
this.dYPoint = '${details.globalPosition.dy.floorToDouble()}';
this.velocity = '';
});
}
/// What should be done at the end of the gesture ?
void _onDragEnd(DragEndDetails details) {
double result = details.velocity.pixelsPerSecond.dx.abs().floorToDouble();
setState(() {
this.velocity = '$result';
});
}
}
You can use the Draggable widget instead. Please try this
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatefulWidget(),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int acceptedData = 0;
#override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Draggable<int>(
// Data is the value this Draggable stores.
data: 10,
feedback: Container(
color: Colors.deepOrange,
height: 100,
width: 100,
child: const Icon(Icons.directions_run),
),
childWhenDragging: Container(
height: 100.0,
width: 100.0,
color: Colors.pinkAccent,
child: const Center(
child: Text('Child When Dragging'),
),
),
child: Container(
height: 100.0,
width: 100.0,
color: Colors.lightGreenAccent,
child: const Center(
child: Text('Draggable'),
),
),
),
DragTarget<int>(
builder: (
BuildContext context,
List<dynamic> accepted,
List<dynamic> rejected,
) {
return Container(
height: 100.0,
width: 100.0,
color: Colors.cyan,
child: Center(
child: Text('Value is updated to: $acceptedData'),
),
);
},
onAccept: (int data) {
setState(() {
acceptedData += data;
});
},
),
],
);
}
}

Why does my code not increase the size of the container?

I am trying to increase the size of the container using GestureDetector's onTap method. But when i tap on the container, nothing happens.
I can't figure out what's wrong? Would you suggest me any other way or any package which can produce the same result.
class DemoPage extends StatefulWidget {
#override
State<DemoPage> createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
CustomContainer container = CustomContainer();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
onTap: () {
setState(() {
container.expandContainer();
});
},
child: container,
)),
);
}
}
class CustomContainer extends StatelessWidget {
Container _container = Container(
color: Colors.yellow,
width: 200.0,
height: 100.0,
);
void expandContainer() {
//Assignment Operator used with Ternary operator
_container = _container ==
Container(
color: Colors.yellow,
width: 200.0,
height: 300.0,
)
? Container(
color: Colors.yellow,
width: 200.0,
height: 100.0,
)
: Container(
color: Colors.yellow,
width: 200.0,
height: 300.0,
);
}
#override
Widget build(BuildContext context) {
return _container;
}
}
I prefer using AnimatedContainer for cases like this.
class DemoPage extends StatefulWidget {
const DemoPage({Key? key}) : super(key: key);
#override
State<DemoPage> createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
bool isExanded = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
onTap: () {
setState(() {
isExanded = !isExanded;
});
print("tapped");
},
child: AnimatedContainer(
color: Colors.yellow,
width: 200.0,
height: isExanded ? 300 : 100.0,
duration: const Duration(seconds: 2),
),
)),
);
}
}

How to switching the stack's widget of index

How to switching the stack's widget smoothly when clicking the smaller widget, mentioned as the image below
When user has clicked Widget B, Widget B will zoom out, and Widget A will zoom in, and the stack position should be changed when clicked the smaller widget.
Any code sample for reference would be appreciated, thanks!
try this:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Widget _a = Container(
color: Colors.red, width: double.infinity, height: double.infinity);
Widget _b = Container(
color: Colors.green, width: double.infinity, height: double.infinity);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
width: 400,
height: 200,
child: Stack(
children: <Widget>[
Container(
width: 400,
height: 200,
child: _a,
),
Positioned(
bottom: 20,
left: 20,
child: GestureDetector(
onTap: (){
Widget _swap = _b;
_b = _a;
_a = _swap;
setState((){});
},
child: Container(
width: 80,
height: 40,
child: _b,
),
),
),
],
),
),
);
}
}

How to change state of programmatically created animatedPositioned widget?

AnimatedPositioned widget animates when a parameter is changed (left for example). This works well unless I create it programatically. How do I change the parameters after creating it?
If you press a button it adds an AnimatedPositioned to the screen. The 'change' button just changed the variable myLeft which should change the position but it doesn't.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Home(),
),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
double myLeft = 20;
List<Widget> listOfBoxes = [];
_createRect(){
setState(() {
final AnimatedPositioned positioned = AnimatedPositioned(
left: myLeft,
top: 25,
height: 50,
width: 100,
duration: const Duration(milliseconds: 600),
child: Container(color: Colors.black,),
);
listOfBoxes.add(positioned
,);
});
}
_change(){
setState(() {
myLeft =200;
print("listOfBoxes==$listOfBoxes");
});
}
void initState() {
super.initState();
SystemChrome.setEnabledSystemUIOverlays([]);
}
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Column(
children: [Row(
children: [
RaisedButton(
child: Text('create rect'),
onPressed: _createRect,
),
RaisedButton(
child: Text('change'),
onPressed: _change,
),
],
),
Container(
color: Colors.blue,
height: size.height * .7,
width: double.infinity,
child: Stack(
children: listOfBoxes,
),
),
]
);
}
}
Here's the code doing what I asked based on pskink's comments.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Home(),
),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
var lefts = [10.0, 20.0];
_change() {
setState(() {
lefts[0] = 200;
});
}
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Column(children: [
Row(
children: [
RaisedButton(
child: Text('change'),
onPressed: _change,
),
],
),
Container(
color: Colors.blue,
height: size.height * .7,
width: double.infinity,
child: Column(
children: [
Expanded(
child: Stack(children: [
for (var i = 0; i < lefts.length; i++)
AnimatedPositioned(
duration: Duration(milliseconds: 200),
left: lefts[i],
top: i * 100.0,
width: 100,
height: 75,
child: Container(color: Colors.red),
)
]),
),
Row(
children: [
RaisedButton(
child: Text('<<'),
onPressed: () => setState(
() => lefts = lefts.map((e) => e - 50).toList())),
RaisedButton(
child: Text('>>'),
onPressed: () => setState(
() => lefts = lefts.map((e) => e + 50).toList())),
],
),
],
),
),
]);
}
}

animate show or hide widgets with 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;
});
}
}